diff --git a/changelog b/changelog
index 442ab6a2b3e9a71e92f7c37c7ff3d892cd51ac85..cd789c39b7400203293fc0a2d613828940c616d6 100644
--- a/changelog
+++ b/changelog
@@ -21,6 +21,12 @@ User api additions
 	can enable it by setting a non-zero timeout (in seconds) at the new
 	ka_time member at context creation time.
 
+ - Two new optional user callbacks added, LWS_CALLBACK_PROTOCOL_DESTROY which
+ 	is called one-time per protocol as the context is being destroyed, and
+	LWS_CALLBACK_PROTOCOL_INIT which is called when the context is created
+	and the protocols are added, again it's a one-time affair.
+	This lets you manage per-protocol allocations properly including
+	cleaning up after yourself when the server goes down.
 
 User api changes
 ----------------
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index e5d148addebc3e1ffd2e84f5218b271c86b3d97c..49a51fe9f6d9ee52a2d1f5f9c6abd0a5f1a1cfd9 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -1041,6 +1041,7 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
 	int n;
 	int m;
 	struct libwebsocket_extension *ext;
+	struct libwebsocket_protocols *protocol = context->protocols;
 
 #ifdef LWS_LATENCY
 	if (context->worst_latency_info[0])
@@ -1067,6 +1068,18 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
 		ext->callback(context, ext, NULL, (enum libwebsocket_extension_callback_reasons)m, NULL, NULL, 0);
 		ext++;
 	}
+
+	/*
+	 * inform all the protocols that they are done and will have no more
+	 * callbacks
+	 */
+
+	while (protocol->callback) {
+		protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY,
+				NULL, NULL, 0);
+		protocol++;
+	}
+
 #endif
 
 #ifdef WIN32
@@ -2023,6 +2036,13 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
 									context;
 		info->protocols[context->count_protocols].protocol_index =
 						       context->count_protocols;
+
+		/*
+		 * inform all the protocols that they are doing their one-time
+		 * initialization if they want to
+		 */
+		info->protocols[context->count_protocols].callback(context,
+			       NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
 	}
 
 #ifndef LWS_NO_EXTENSIONS
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index c39d13a8fc0e6ad57ec4f6fcfa872a042050c488..8ead4100cf32c457245da128a582a903a057c44c 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -142,6 +142,8 @@ enum libwebsocket_callback_reasons {
 	LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
 	LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
 	LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
+	LWS_CALLBACK_PROTOCOL_INIT,
+	LWS_CALLBACK_PROTOCOL_DESTROY,
 	/* external poll() management support */
 	LWS_CALLBACK_ADD_POLL_FD,
 	LWS_CALLBACK_DEL_POLL_FD,
@@ -534,6 +536,14 @@ struct libwebsocket_extension;
  *		support included in the header to the server.  Notice this
  *		callback comes to protocols[0].
  *
+ *	LWS_CALLBACK_PROTOCOL_INIT:	One-time call per protocol so it can
+ *		do initial setup / allocations etc
+ *
+ *	LWS_CALLBACK_PROTOCOL_DESTROY:	One-time call per protocol indicating
+ *		this protocol won't get used at all after this callback, the
+ *		context is getting destroyed.  Take the opportunity to
+ *		deallocate everything that was allocated by the protocol.
+ *
  *	The next four reasons are optional and only need taking care of if you
  * 	will be integrating libwebsockets sockets into an external polling
  * 	array.
diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html
index a3f6415ef1523334cdb192e501d8e020abbc0d13..726b68864d192304ba9d384e4ad3c78f36e1e631 100644
--- a/libwebsockets-api-doc.html
+++ b/libwebsockets-api-doc.html
@@ -752,6 +752,18 @@ claim to support that extension by returning non-zero.  If
 unhandled, by default 0 will be returned and the extension
 support included in the header to the server.  Notice this
 callback comes to protocols[0].
+</blockquote>
+<h3>LWS_CALLBACK_PROTOCOL_INIT</h3>
+<blockquote>
+One-time call per protocol so it can
+do initial setup / allocations etc
+</blockquote>
+<h3>LWS_CALLBACK_PROTOCOL_DESTROY</h3>
+<blockquote>
+One-time call per protocol indicating
+this protocol won't get used at all after this callback, the
+context is getting destroyed.  Take the opportunity to
+deallocate everything that was allocated by the protocol.
 <p>
 The next four reasons are optional and only need taking care of if you
 will be integrating libwebsockets sockets into an external polling
diff --git a/test-server/test-server.c b/test-server/test-server.c
index d786f4b7e7680f589f9adfc5e5a5fa7104ddd7ca..388303e820b2da7a7d142e461b8763f3b4377e13 100644
--- a/test-server/test-server.c
+++ b/test-server/test-server.c
@@ -356,6 +356,13 @@ callback_lws_mirror(struct libwebsocket_context *context,
 		pss->wsi = wsi;
 		break;
 
+	case LWS_CALLBACK_PROTOCOL_DESTROY:
+		lwsl_notice("mirror protocol cleaning up\n");
+		for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++)
+			if (ringbuffer[n].payload)
+				free(ringbuffer[n].payload);
+		break;
+
 	case LWS_CALLBACK_SERVER_WRITEABLE:
 		if (close_testing)
 			break;