diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h
index 8d8684602b..921f1ff696 100644
--- a/lib/isc/netmgr/netmgr-int.h
+++ b/lib/isc/netmgr/netmgr-int.h
@@ -932,6 +932,7 @@ struct isc_nmsocket {
 		isc_tls_t *tls;
 		isc_tlsctx_t *ctx;
 		isc_nmsocket_t *tlslistener;
+		isc_nmsocket_t *tlssocket;
 		atomic_bool result_updated;
 		enum {
 			TLS_INIT,
diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c
index 252b52da9f..6ca7e03b59 100644
--- a/lib/isc/netmgr/tlsstream.c
+++ b/lib/isc/netmgr/tlsstream.c
@@ -200,7 +200,6 @@ tls_failed_read_cb(isc_nmsocket_t *sock, const isc_result_t result) {
 
 	if (destroy) {
 		isc__nmsocket_prep_destroy(sock);
-		isc__nmsocket_detach(&sock);
 	}
 }
 
@@ -401,21 +400,7 @@ tls_do_bio(isc_nmsocket_t *sock, isc_region_t *received_data,
 				send_data->cb.send(send_data->handle, result,
 						   send_data->cbarg);
 				send_data = NULL;
-				/* This situation might occur only when SSL
-				 * shutdown was already sent (see
-				 * tls_send_outgoing()), and we are in the
-				 * process of shutting down the connection (in
-				 * this case tls_senddone() will be called), but
-				 * some code tries to send data over the
-				 * connection and called isc_tls_send(). The
-				 * socket will be detached there, in
-				 * tls_senddone().*/
-				if (sent_shutdown || received_shutdown) {
-					return;
-				} else {
-					isc__nmsocket_detach(&sock);
-					return;
-				}
+				return;
 			}
 		}
 
@@ -614,6 +599,12 @@ tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
 
 	tlssock->tlsstream.ctx = tlslistensock->tlsstream.ctx;
 
+	/*
+	 * Hold a reference to tlssock in the TCP socket: it will
+	 * detached in isc__nm_tls_cleanup_data().
+	 */
+	handle->sock->tlsstream.tlssocket = tlssock;
+
 	result = initialize_tls(tlssock, true);
 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
 	/* TODO: catch failure code, detach tlssock, and log the error */
@@ -814,7 +805,7 @@ tls_close_direct(isc_nmsocket_t *sock) {
 		isc__nmsocket_detach(&sock->listener);
 	}
 
-	/* further cleanup performed in isc__nm_tls_cleanup_data() */
+	/* Further cleanup performed in isc__nm_tls_cleanup_data() */
 	atomic_store(&sock->closed, true);
 	atomic_store(&sock->active, false);
 	sock->tlsstream.state = TLS_CLOSED;
@@ -939,6 +930,12 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
 	isc_nmhandle_attach(handle, &tlssock->outerhandle);
 	atomic_store(&tlssock->active, true);
 
+	/*
+	 * Hold a reference to tlssock in the TCP socket: it will
+	 * detached in isc__nm_tls_cleanup_data().
+	 */
+	handle->sock->tlsstream.tlssocket = tlssock;
+
 	tls_do_bio(tlssock, NULL, NULL, false);
 	return;
 error:
@@ -1016,6 +1013,13 @@ isc__nm_tls_cleanup_data(isc_nmsocket_t *sock) {
 			sock->tlsstream.bio_out = NULL;
 			sock->tlsstream.bio_in = NULL;
 		}
+	} else if (sock->type == isc_nm_tcpsocket &&
+		   sock->tlsstream.tlssocket != NULL) {
+		/*
+		 * The TLS socket can't be destroyed until its underlying TCP
+		 * socket is, to avoid possible use-after-free errors.
+		 */
+		isc__nmsocket_detach(&sock->tlsstream.tlssocket);
 	}
 }
 
-- 
2.35.3

