diff --git a/apps/ssb.json b/apps/ssb.json
index 0e6055dd..62252dac 100644
--- a/apps/ssb.json
+++ b/apps/ssb.json
@@ -1,5 +1,5 @@
 {
 	"type": "tildefriends-app",
 	"emoji": "🦀",
-	"previous": "&QuEaXfdWGAl42dkJBoHocZbtKRT3zT25BNgCo88CSfE=.sha256"
+	"previous": "&zCaET5zt2iWthUzrTd/BWqfmSjeFryuVru6FrlQJOBI=.sha256"
 }
diff --git a/apps/ssb/tf-tab-connections.js b/apps/ssb/tf-tab-connections.js
index d03e3001..3c8e71ff 100644
--- a/apps/ssb/tf-tab-connections.js
+++ b/apps/ssb/tf-tab-connections.js
@@ -175,6 +175,9 @@ class TfTabConnectionsElement extends LitElement {
 					.map((x) => html`
${this.render_connection(x)}`)}
 				${this.render_room_peers(connection.id)}
 			
+			
+				
${connection.destroy_reason}
+			
 
 		`;
 	}
 
diff --git a/src/ssb.c b/src/ssb.c
index f67e5eae..3dbe5534 100644
--- a/src/ssb.c
+++ b/src/ssb.c
@@ -273,6 +273,7 @@ typedef struct _tf_ssb_connection_t
 	uv_async_t async;
 	uv_async_t scheduled_async;
 	uv_timer_t handshake_timer;
+	uv_timer_t linger_timer;
 	bool closing;
 
 	tf_ssb_connection_t* tunnel_connection;
@@ -1839,10 +1840,21 @@ JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* pr
 	return root;
 }
 
+static void _tf_ssb_connection_linger_timer(uv_timer_t* timer)
+{
+	tf_ssb_connection_t* connection = timer->data;
+	uv_close((uv_handle_t*)&connection->linger_timer, _tf_ssb_connection_on_close);
+}
+
 static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason)
 {
 	tf_ssb_t* ssb = connection->ssb;
-	connection->closing = true;
+	if (!connection->closing)
+	{
+		connection->closing = true;
+		uv_timer_start(&connection->linger_timer, _tf_ssb_connection_linger_timer, 5000, 0);
+		_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_update, connection);
+	}
 	if (connection->connect_callback)
 	{
 		PRE_CALLBACK(connection->ssb, connection->connect_callback);
@@ -1853,7 +1865,7 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
 	}
 	if (!connection->destroy_reason)
 	{
-		connection->destroy_reason = reason;
+		connection->destroy_reason = tf_strdup(reason);
 	}
 	_tf_ssb_connection_dispatch_scheduled(connection);
 	tf_free(connection->scheduled);
@@ -1879,14 +1891,6 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
 				tf_ssb_connection_remove_request(*it, (*it)->requests[i].request_number);
 			}
 		}
-		if (*it == connection)
-		{
-			*it = connection->next;
-			connection->next = NULL;
-			ssb->connections_count--;
-			_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_remove, connection);
-			break;
-		}
 	}
 	bool again = true;
 	while (again)
@@ -1934,16 +1938,29 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
 	}
 
 	if (JS_IsUndefined(connection->object) && !connection->async.data && !connection->scheduled_async.data && !connection->tcp.data && !connection->connect.data &&
-		!connection->handshake_timer.data && connection->ref_count == 0)
+		!connection->handshake_timer.data && !connection->linger_timer.data && connection->ref_count == 0)
 	{
 		tf_free(connection->message_requests);
 		connection->message_requests = NULL;
 		connection->message_requests_count = 0;
 
+		for (tf_ssb_connection_t** it = &connection->ssb->connections; *it; it = &(*it)->next)
+		{
+			if (*it == connection)
+			{
+				*it = connection->next;
+				connection->next = NULL;
+				ssb->connections_count--;
+				_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_remove, connection);
+				break;
+			}
+		}
+
 		if (--connection->ssb->connection_ref_count == 0 && connection->ssb->shutting_down_deferred)
 		{
 			tf_ssb_destroy(connection->ssb);
 		}
+		tf_free((void*)connection->destroy_reason);
 		tf_free(connection);
 	}
 }
@@ -2723,6 +2740,9 @@ static tf_ssb_connection_t* _tf_ssb_connection_create(
 	uv_timer_init(ssb->loop, &connection->handshake_timer);
 	uv_timer_start(&connection->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
 
+	connection->linger_timer.data = connection;
+	uv_timer_init(ssb->loop, &connection->linger_timer);
+
 	connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
 	JS_SetOpaque(connection->object, connection);
 	char public_key_str[k_id_base64_len] = { 0 };
@@ -2796,6 +2816,9 @@ tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char*
 	uv_timer_init(ssb->loop, &tunnel->handshake_timer);
 	uv_timer_start(&tunnel->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
 
+	tunnel->linger_timer.data = tunnel;
+	uv_timer_init(ssb->loop, &tunnel->linger_timer);
+
 	tunnel->object = JS_NewObjectClass(ssb->context, _connection_class_id);
 	JS_SetOpaque(tunnel->object, tunnel);
 	JS_SetPropertyStr(context, tunnel->object, "id", JS_NewString(context, target_id));
@@ -2956,6 +2979,9 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
 	uv_timer_init(ssb->loop, &connection->handshake_timer);
 	uv_timer_start(&connection->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
 
+	connection->linger_timer.data = connection;
+	uv_timer_init(ssb->loop, &connection->linger_timer);
+
 	struct sockaddr_storage addr = { 0 };
 	int size = sizeof(addr);
 	if (uv_tcp_getpeername(&connection->tcp, (struct sockaddr*)&addr, &size) == 0)
@@ -4265,6 +4291,11 @@ void tf_ssb_connection_adjust_write_count(tf_ssb_connection_t* connection, int d
 	uv_async_send(&connection->scheduled_async);
 }
 
+const char* tf_ssb_connection_get_destroy_reason(tf_ssb_connection_t* connection)
+{
+	return connection ? connection->destroy_reason : NULL;
+}
+
 void tf_ssb_sync_start(tf_ssb_t* ssb)
 {
 	tf_ssb_connections_sync_start(ssb->connections_tracker);
diff --git a/src/ssb.h b/src/ssb.h
index 3ed1652a..dc65fcde 100644
--- a/src/ssb.h
+++ b/src/ssb.h
@@ -1093,6 +1093,13 @@ void tf_ssb_connection_adjust_read_backpressure(tf_ssb_connection_t* connection,
 */
 void tf_ssb_connection_adjust_write_count(tf_ssb_connection_t* connection, int delta);
 
+/**
+** Get the reason why a connection is going away.
+** @param connection The connection.
+** @return The reason or NULL.
+*/
+const char* tf_ssb_connection_get_destroy_reason(tf_ssb_connection_t* connection);
+
 /**
 ** Initiate a tunnel connection.
 ** @param ssb The SSB instance.
diff --git a/src/ssb.js.c b/src/ssb.js.c
index cb00ca5d..34dea727 100644
--- a/src/ssb.js.c
+++ b/src/ssb.js.c
@@ -1120,6 +1120,11 @@ static JSValue _tf_ssb_connections(JSContext* context, JSValueConst this_val, in
 			int flags = tf_ssb_connection_get_flags(connection);
 			JS_SetPropertyStr(context, flags_object, "one_shot", JS_NewBool(context, (flags & k_tf_ssb_connect_flag_one_shot) != 0));
 			JS_SetPropertyStr(context, object, "flags", flags_object);
+			const char* destroy_reason = tf_ssb_connection_get_destroy_reason(connection);
+			if (destroy_reason)
+			{
+				JS_SetPropertyStr(context, object, "destroy_reason", JS_NewString(context, destroy_reason));
+			}
 			JS_SetPropertyUint32(context, result, i, object);
 		}
 	}