diff --git a/README.coding.md b/README.coding.md
index f369937d5b65cdafc860ce2f93e503870aa8b2a7..d03b613ac7dc3cb4e1c851fe667660a93d69fdaf 100644
--- a/README.coding.md
+++ b/README.coding.md
@@ -394,3 +394,25 @@ LWS_SERVER_OPTION_LIBEV
 LWS_SERVER_OPTION_LIBUV
 
 to indicate it will use either of the event libraries.
+
+
+Extension option control from user code
+---------------------------------------
+
+User code may set per-connection extension options now, using a new api
+"lws_set_extension_option()".
+
+This should be called from the ESTABLISHED callback like this
+
+ lws_set_extension_option(wsi, "permessage-deflate",
+                          "rx_buf_size", "12"); /* 1 << 12 */
+
+If the extension is not active (missing or not negotiated for the
+connection, or extensions are disabled on the library) the call is
+just returns -1.  Otherwise the connection's extension has its
+named option changed.
+
+The extension may decide to alter or disallow the change, in the
+example above permessage-deflate restricts the size of his rx
+output buffer also considering the protocol's rx_buf_size member.
+
diff --git a/changelog b/changelog
index 3142d559be8c4a01875e7cf896377765d34aa081..a13eabef1ca1b3ed0c58394d1b8eefddc35b2806 100644
--- a/changelog
+++ b/changelog
@@ -185,6 +185,24 @@ LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS.  If you give this, non-ssl
 connections to the server listen port are accepted and receive a 301
 redirect to / on the same host and port using https://
 
+8) User code may set per-connection extension options now, using a new api
+"lws_set_extension_option()".
+
+This should be called from the ESTABLISHED callback like this
+
+ lws_set_extension_option(wsi, "permessage-deflate",
+                          "rx_buf_size", "12"); /* 1 << 12 */
+
+If the extension is not active (missing or not negotiated for the
+connection, or extensions are disabled on the library) the call is
+just returns -1.  Otherwise the connection's extension has its
+named option changed.
+
+The extension may decide to alter or disallow the change, in the
+example above permessage-deflate restricts the size of his rx
+output buffer also considering the protocol's rx_buf_size member.
+
+
 New application lwsws
 ---------------------
 
diff --git a/lib/extension-permessage-deflate.c b/lib/extension-permessage-deflate.c
index 3621410f5de88497b9946eda4ac5c511fee6c71f..65f28caaecdf36dd3a11dcd7ce7a18018b668617 100644
--- a/lib/extension-permessage-deflate.c
+++ b/lib/extension-permessage-deflate.c
@@ -41,6 +41,28 @@ const struct lws_ext_options lws_ext_pm_deflate_options[] = {
 	{ NULL, 0 }, /* sentinel */
 };
 
+static void
+lws_extension_pmdeflate_restrict_args(struct lws *wsi,
+				      struct lws_ext_pm_deflate_priv *priv)
+{
+	int n, extra;
+
+	/* cap the RX buf at the nearest power of 2 to protocol rx buf */
+
+	n = LWS_MAX_SOCKET_IO_BUF;
+	if (wsi->protocol->rx_buffer_size)
+		n =  wsi->protocol->rx_buffer_size;
+
+	extra = 7;
+	while (n >= 1 << (extra + 1))
+		extra++;
+
+	if (extra < priv->args[PMD_RX_BUF_PWR2]) {
+		priv->args[PMD_RX_BUF_PWR2] = extra;
+		lwsl_err(" Capping pmd rx to %d\n", 1 << extra);
+	}
+}
+
 LWS_VISIBLE int
 lws_extension_callback_pm_deflate(struct lws_context *context,
 				  const struct lws_extension *ext,
@@ -56,6 +78,20 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 	struct lws_ext_option_arg *oa;
 
 	switch (reason) {
+	case LWS_EXT_CB_NAMED_OPTION_SET:
+		oa = in;
+		if (!oa->option_name)
+			break;
+		for (n = 0; n < ARRAY_SIZE(lws_ext_pm_deflate_options); n++)
+			if (!strcmp(lws_ext_pm_deflate_options[n].name, oa->option_name))
+				break;
+
+		if (n == ARRAY_SIZE(lws_ext_pm_deflate_options))
+			break;
+		oa->option_index = n;
+
+		/* fallthru */
+
 	case LWS_EXT_CB_OPTION_SET:
 		oa = in;
 		lwsl_info("%s: option set: idx %d, %s, len %d\n", __func__,
@@ -64,7 +100,10 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 			priv->args[oa->option_index] = atoi(oa->start);
 		else
 			priv->args[oa->option_index] = 1;
+
+		lws_extension_pmdeflate_restrict_args(wsi, priv);
 		break;
+
 	case LWS_EXT_CB_OPTION_CONFIRM:
 		if (priv->args[PMD_SERVER_MAX_WINDOW_BITS] < 8 ||
 		    priv->args[PMD_SERVER_MAX_WINDOW_BITS] > 15 ||
@@ -94,7 +133,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
 		/* fill in pointer to options list */
 		if (in)
-			*((const struct lws_ext_options **)in) = lws_ext_pm_deflate_options;
+			*((const struct lws_ext_options **)in) =
+					lws_ext_pm_deflate_options;
 
 		/* fallthru */
 
@@ -114,22 +154,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 		priv->args[PMD_COMP_LEVEL] = 1;
 		priv->args[PMD_MEM_LEVEL] = 8;
 
-		/* cap the RX buf at the nearest power of 2 to protocol rx buf */
-
-		n = LWS_MAX_SOCKET_IO_BUF;
-		if (wsi->protocol->rx_buffer_size)
-			n =  wsi->protocol->rx_buffer_size;
-
-		extra = 7;
-		while (n >= 1 << (extra + 1))
-			extra++;
-
-		if (extra < priv->args[PMD_RX_BUF_PWR2]) {
-			priv->args[PMD_RX_BUF_PWR2] = extra;
-			lwsl_err(" Capping pmd rx to %d\n", 1 << extra);
-		}
-		lwsl_err("   ok\n");
-
+		lws_extension_pmdeflate_restrict_args(wsi, priv);
 		break;
 
 	case LWS_EXT_CB_DESTROY:
diff --git a/lib/extension.c b/lib/extension.c
index df24dd5514796e8f1b9d8ca25e42b1880525c926..580e8a6c0381eb6fe04c56f84e9efb2548bc2308 100644
--- a/lib/extension.c
+++ b/lib/extension.c
@@ -27,6 +27,8 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
 		     pending_close_quote = 0;
 	struct lws_ext_option_arg oa;
 
+	oa.option_name = NULL;
+
 	while (opts[count_options].name)
 		count_options++;
 	while (len) {
@@ -315,3 +317,37 @@ lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r
 
 	return handled;
 }
+
+/**
+ * lws_set_extension_option(): set extension option if possible
+ *
+ * @wsi:	websocket connection
+ * @ext_name:	name of ext, like "permessage-deflate"
+ * @opt_name:	name of option, like "rx_buf_size"
+ * @opt_val:	value to set option to
+ */
+
+int
+lws_set_extension_option(struct lws *wsi, const char *ext_name,
+			 const char *opt_name, const char *opt_val)
+{
+	struct lws_ext_option_arg oa;
+	int idx = 0;
+
+	/* first identify if the ext is active on this wsi */
+	while (idx < wsi->count_act_ext &&
+	       strcmp(wsi->active_extensions[idx]->name, ext_name))
+		idx++;
+
+	if (idx == wsi->count_act_ext)
+		return -1; /* request ext not active on this wsi */
+
+	oa.option_name = opt_name;
+	oa.option_index = 0;
+	oa.start = opt_val;
+	oa.len = 0;
+
+	return wsi->active_extensions[idx]->callback(
+			wsi->context, wsi->active_extensions[idx], wsi,
+			LWS_EXT_CB_NAMED_OPTION_SET, wsi->act_ext_user[idx], &oa, 0);
+}
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 995881641e94aa104bf1bcac6cbba8100be6c240..c537c1b5087fe6e2cd6a5da04764dc44dfe3544a 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -2024,3 +2024,12 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
 	return 0;
 }
 #endif
+
+#ifdef LWS_NO_EXTENSIONS
+LWS_EXTERN int
+lws_set_extension_option(struct lws *wsi, const char *ext_name,
+			 const char *opt_name, const char *opt_val)
+{
+	return -1;
+}
+#endif
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 5cbaaadcf177f231d3e44c646423bae2a0972155..41a2c27b8fc4c71c28f9d33a624ce6bb784c81f1 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -514,6 +514,7 @@ enum lws_extension_callback_reasons {
 	LWS_EXT_CB_OPTION_DEFAULT			= 23,
 	LWS_EXT_CB_OPTION_SET				= 24,
 	LWS_EXT_CB_OPTION_CONFIRM			= 25,
+	LWS_EXT_CB_NAMED_OPTION_SET			= 26,
 
 	/****** add new things just above ---^ ******/
 };
@@ -1279,6 +1280,7 @@ struct lws_ext_options {
 };
 
 struct lws_ext_option_arg {
+	const char *option_name; /* may be NULL, option_index used then */
 	int option_index;
 	const char *start;
 	int len;
@@ -1331,6 +1333,10 @@ extern int lws_extension_callback_pm_deflate(
 	struct lws *wsi, enum lws_extension_callback_reasons reason,
 	void *user, void *in, size_t len);
 
+LWS_EXTERN int
+lws_set_extension_option(struct lws *wsi, const char *ext_name,
+			 const char *opt_name, const char *opt_val);
+
 
 /**
  * struct lws_context_creation_info - parameters to create context with