diff --git a/include/libwebsockets/lws-threadpool.h b/include/libwebsockets/lws-threadpool.h
index 258ee1abc21ce633773cd520cbc1b506ecd7fa45..eb6c6e1a161e68bc4a1cb5f8c9a74e223b415b7f 100644
--- a/include/libwebsockets/lws-threadpool.h
+++ b/include/libwebsockets/lws-threadpool.h
@@ -58,7 +58,10 @@ enum lws_threadpool_task_return {
 	/** No more work to do... */
 	LWS_TP_RETURN_FINISHED,
 	/** Responding to request to stop */
-	LWS_TP_RETURN_STOPPED
+	LWS_TP_RETURN_STOPPED,
+
+	/* OR on to indicate this task wishes to outlive its wsi */
+	LWS_TP_RETURN_FLAG_OUTLIVE = 64
 };
 
 struct lws_threadpool_create_args {
@@ -70,6 +73,9 @@ struct lws_threadpool_task_args {
 	struct lws *wsi;	/**< user must set to wsi task is bound to */
 	void *user;		/**< user may set (user-private pointer) */
 	const char *name;	/**< user may set to describe task */
+	char async_task;	/**< set to allow the task to shrug off the loss
+				     of the associated wsi and continue to
+				     completion */
 	enum lws_threadpool_task_return (*task)(void *user,
 					enum lws_threadpool_task_status s);
 	/**< user must set to actual task function */
diff --git a/lib/misc/threadpool/README.md b/lib/misc/threadpool/README.md
index 7d51c17e3af3c761f089d55a968ee4344d092361..7b5dece153f6495c31ca5e1529d7006608e6c5c6 100644
--- a/lib/misc/threadpool/README.md
+++ b/lib/misc/threadpool/README.md
@@ -126,6 +126,13 @@ LWS_TP_RETURN_SYNC|Task wants to trigger a WRITABLE callback and block until lws
 LWS_TP_RETURN_FINISHED|Task has finished, successfully as far as it goes
 LWS_TP_RETURN_STOPPED|Task has finished, aborting in response to a request to stop
 
+The SYNC or CHECKING_IN return may also have a flag `LWS_TP_RETURN_FLAG_OUTLIVE`
+applied to it, which indicates to threadpool that this task wishes to remain
+unstopped after the wsi closes.  This is useful in the case where the task
+understands it will take a long time to complete, and wants to return a
+complete status and maybe close the connection, perhaps with a token identifying
+the task.  The task can then be monitored separately by using the token.
+
 #### Synchronizing
 
 The task can choose to "SYNC" with the lws service thread, in other words
diff --git a/lib/misc/threadpool/threadpool.c b/lib/misc/threadpool/threadpool.c
index 127bf025b571e4a67b97a58d700003775142d42e..c050c4a6079e23873987d5343576d50ac5ee6887 100644
--- a/lib/misc/threadpool/threadpool.c
+++ b/lib/misc/threadpool/threadpool.c
@@ -49,6 +49,7 @@ struct lws_threadpool_task {
 	int late_sync_retries;
 
 	char wanted_writeable_cb;
+	char outlive;
 };
 
 struct lws_pool {
@@ -538,17 +539,29 @@ lws_threadpool_worker(void *d)
 			lws_usec_t then;
 			int n;
 
-			if (tp->destroying || !task->args.wsi)
+			if (tp->destroying || !task->args.wsi) {
+				lwsl_info("%s: stopping on wsi gone\n", __func__);
 				state_transition(task, LWS_TP_STATUS_STOPPING);
+			}
 
 			then = lws_now_usecs();
 			n = task->args.task(task->args.user, task->status);
+			lwsl_debug("   %d, status %d\n", n, task->status);
 			us_accrue(&task->acc_running, then);
-			switch (n) {
+			if (n & LWS_TP_RETURN_FLAG_OUTLIVE)
+				task->outlive = 1;
+			switch (n & 7) {
 			case LWS_TP_RETURN_CHECKING_IN:
 				/* if not destroying the tp, continue */
 				break;
 			case LWS_TP_RETURN_SYNC:
+				if (!task->args.wsi) {
+					lwsl_debug("%s: task that wants to "
+						    "outlive lost wsi asked "
+						    "to sync: bypassed\n",
+						    __func__);
+					break;
+				}
 				/* block until writable acknowledges */
 				then = lws_now_usecs();
 				lws_threadpool_worker_sync(pool, task);
@@ -777,6 +790,17 @@ lws_threadpool_dequeue(struct lws *wsi)
 	tp = task->tp;
 	pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
 
+	if (task->outlive && !tp->destroying) {
+
+		/* disconnect from wsi, and wsi from task */
+
+		wsi->tp_task = NULL;
+		task->args.wsi = NULL;
+
+		goto bail;
+	}
+
+
 	c = &tp->task_queue_head;
 
 	/* is he queued waiting for a chance to run?  Mark him as stopped and