diff --git a/lib/client-parser.c b/lib/client-parser.c
index 4036941cc50a7e83f1724605671db3be5e72dfa8..b467aa092546663924a24ad30fa0982441c2ae45 100644
--- a/lib/client-parser.c
+++ b/lib/client-parser.c
@@ -321,10 +321,10 @@ int lws_client_rx_sm(struct lws *wsi, unsigned char c)
 
 		/*
 		 * if there's no protocol max frame size given, we are
-		 * supposed to default to LWS_MAX_SOCKET_IO_BUF
+		 * supposed to default to context->pt_serv_buf_size
 		 */
 		if (!wsi->protocol->rx_buffer_size &&
-		    wsi->u.ws.rx_ubuf_head != LWS_MAX_SOCKET_IO_BUF)
+		    wsi->u.ws.rx_ubuf_head != wsi->context->pt_serv_buf_size)
 			break;
 
 		if (wsi->protocol->rx_buffer_size &&
diff --git a/lib/client.c b/lib/client.c
index adb275954b9f2ff4c06d789a02db326abfa4a93d..4ce50eb5a98ea182e48a953a80093a035368933d 100644
--- a/lib/client.c
+++ b/lib/client.c
@@ -107,7 +107,7 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
 			return 0;
 		}
 
-		n = recv(wsi->sock, sb, LWS_MAX_SOCKET_IO_BUF, 0);
+		n = recv(wsi->sock, sb, context->pt_serv_buf_size, 0);
 		if (n < 0) {
 			if (LWS_ERRNO == LWS_EAGAIN) {
 				lwsl_debug("Proxy read returned EAGAIN... retrying\n");
@@ -368,11 +368,11 @@ lws_client_interpret_server_handshake(struct lws *wsi)
 {
 	int n, len, okay = 0, isErrorCodeReceived = 0, port = 0, ssl = 0;
 	int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
+	struct lws_context *context = wsi->context;
 	const char *pc, *prot, *ads = NULL, *path;
 	struct allocated_headers *ah;
 	char *p;
 #ifndef LWS_NO_EXTENSIONS
-	struct lws_context *context = wsi->context;
 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
 	char *sb = (char *)&pt->serv_buf[0];
 	const struct lws_ext_options *opts;
@@ -622,7 +622,7 @@ check_extensions:
 	 * and go through matching them or identifying bogons
 	 */
 
-	if (lws_hdr_copy(wsi, sb, LWS_MAX_SOCKET_IO_BUF, WSI_TOKEN_EXTENSIONS) < 0) {
+	if (lws_hdr_copy(wsi, sb, context->pt_serv_buf_size, WSI_TOKEN_EXTENSIONS) < 0) {
 		lwsl_warn("ext list from server failed to copy\n");
 		goto bail2;
 	}
@@ -789,7 +789,7 @@ check_accept:
 	 */
 	n = wsi->protocol->rx_buffer_size;
 	if (!n)
-		n = LWS_MAX_SOCKET_IO_BUF;
+		n = context->pt_serv_buf_size;
 	n += LWS_PRE;
 	wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
 	if (!wsi->u.ws.rx_ubuf) {
@@ -993,7 +993,7 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
 	/* give userland a chance to append, eg, cookies */
 
 	wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
-				wsi->user_space, &p, (pkt + LWS_MAX_SOCKET_IO_BUF) - p - 12);
+				wsi->user_space, &p, (pkt + context->pt_serv_buf_size) - p - 12);
 
 	p += sprintf(p, "\x0d\x0a");
 
diff --git a/lib/context.c b/lib/context.c
index bf359265aeaaf28244ae9bd4771dc44ce9b9d390..47976fbb194a5f3fc91d344aac4f4fcff6f46061 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -272,7 +272,7 @@ static const struct lws_protocols protocols_dummy[] = {
 		"http-only",		/* name */
 		callback_http_dummy,		/* callback */
 		0,	/* per_session_data_size */
-		4096,			/* max frame size / rx buffer */
+		0,			/* max frame size / rx buffer */
 	},
 	/*
 	 * the other protocols are provided by lws plugins
@@ -598,6 +598,11 @@ lws_create_context(struct lws_context_creation_info *info)
 		return NULL;
 	}
 
+	if (info->pt_serv_buf_size)
+		context->pt_serv_buf_size = info->pt_serv_buf_size;
+	else
+		context->pt_serv_buf_size = 4096;
+
 	context->time_up = time(NULL);
 #ifndef LWS_NO_DAEMONIZE
 	if (pid_daemon) {
@@ -649,7 +654,7 @@ lws_create_context(struct lws_context_creation_info *info)
 	 * and header data pool
 	 */
 	for (n = 0; n < context->count_threads; n++) {
-		context->pt[n].serv_buf = lws_zalloc(LWS_MAX_SOCKET_IO_BUF);
+		context->pt[n].serv_buf = lws_zalloc(context->pt_serv_buf_size);
 		if (!context->pt[n].serv_buf) {
 			lwsl_err("OOM\n");
 			return NULL;
@@ -714,10 +719,10 @@ lws_create_context(struct lws_context_creation_info *info)
 
 	lwsl_info(" mem: context:         %5u bytes (%d ctx + (%d thr x %d))\n",
 		  sizeof(struct lws_context) +
-		  (context->count_threads * LWS_MAX_SOCKET_IO_BUF),
+		  (context->count_threads * context->pt_serv_buf_size),
 		  sizeof(struct lws_context),
 		  context->count_threads,
-		  LWS_MAX_SOCKET_IO_BUF);
+		  context->pt_serv_buf_size);
 
 	lwsl_info(" mem: http hdr rsvd:   %5u bytes (%u thr x (%u + %u) x %u))\n",
 		    (context->max_http_header_data +
diff --git a/lib/extension-permessage-deflate.c b/lib/extension-permessage-deflate.c
index 65f28caaecdf36dd3a11dcd7ce7a18018b668617..ec9c809227e5c425ab0a911eecc5acb9ec25745e 100644
--- a/lib/extension-permessage-deflate.c
+++ b/lib/extension-permessage-deflate.c
@@ -49,7 +49,7 @@ lws_extension_pmdeflate_restrict_args(struct lws *wsi,
 
 	/* cap the RX buf at the nearest power of 2 to protocol rx buf */
 
-	n = LWS_MAX_SOCKET_IO_BUF;
+	n = wsi->context->pt_serv_buf_size;
 	if (wsi->protocol->rx_buffer_size)
 		n =  wsi->protocol->rx_buffer_size;
 
@@ -115,7 +115,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 	case LWS_EXT_CB_CLIENT_CONSTRUCT:
 	case LWS_EXT_CB_CONSTRUCT:
 
-		n = LWS_MAX_SOCKET_IO_BUF;
+		n = context->pt_serv_buf_size;
 		if (wsi->protocol->rx_buffer_size)
 			n =  wsi->protocol->rx_buffer_size;
 
diff --git a/lib/header.c b/lib/header.c
index bacbe978fc327523b312f6bd30325c3e0fae3b69..1a45c95e1e82c146c25506c25bdb7cb7a9a6cdec 100644
--- a/lib/header.c
+++ b/lib/header.c
@@ -219,7 +219,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
 	unsigned char *p = pt->serv_buf + LWS_PRE;
 	unsigned char *start = p, *body = p + 512;
-	unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE;
+	unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
 	int n, m, len;
 	char slen[20];
 
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 40cfba71f122b3036d320845918f94cdbf39a733..21debc13e7c8b971982152f7817f71e2c0d4d3b5 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -1496,6 +1496,11 @@ struct lws_http_mount {
  * @mounts:	VHOST: optional linked list of mounts for this vhost
  * @server_string: CONTEXT: string used in HTTP headers to identify server
  *		software, if NULL, "libwebsockets".
+ * @pt_serv_buf_size: CONTEXT: 0 = default of 4096.  This buffer is used by
+ *		various service related features including file serving, it
+ *		defines the max chunk of file that can be sent at once.
+ *		At the risk of lws having to buffer failed large sends, it
+ *		can be increased to, eg, 128KiB to improve throughput.
  */
 
 struct lws_context_creation_info {
@@ -1538,6 +1543,7 @@ struct lws_context_creation_info {
 	const char *log_filepath;			/* VH */
 	const struct lws_http_mount *mounts;		/* VH */
 	const char *server_string;			/* context */
+	unsigned int pt_serv_buf_size;			/* context */
 
 	/* Add new things just above here ---^
 	 * This is part of the ABI, don't needlessly break compatibility
diff --git a/lib/output.c b/lib/output.c
index a29cf30ebe149a5241ac93bfaa36adf93fe71c73..3398fd1357f46e73f411e9508b1179b94ca5a198 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -129,7 +129,7 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
 	/* limit sending */
 	n = wsi->protocol->rx_buffer_size;
 	if (!n)
-		n = LWS_MAX_SOCKET_IO_BUF;
+		n = context->pt_serv_buf_size;
 	n += LWS_PRE + 4;
 	if (n > len)
 		n = len;
@@ -585,7 +585,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
 
 		if (lws_plat_file_read(wsi, wsi->u.http.fd, &amount,
 				       pt->serv_buf,
-				       LWS_MAX_SOCKET_IO_BUF) < 0)
+				       context->pt_serv_buf_size) < 0)
 			return -1; /* caller will close */
 
 		n = (int)amount;
diff --git a/lib/parsers.c b/lib/parsers.c
index a23f4c92d963d48766d698d3e29af83e9e9684c0..0dea47f18b010ce76d5f97eee31e2c75807bf5a6 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -1286,12 +1286,11 @@ handle_first:
 
 		/*
 		 * if there's no protocol max frame size given, we are
-		 * supposed to default to LWS_MAX_SOCKET_IO_BUF
+		 * supposed to default to context->pt_serv_buf_size
 		 */
 
 		if (!wsi->protocol->rx_buffer_size &&
-			 		wsi->u.ws.rx_ubuf_head !=
-			 				  LWS_MAX_SOCKET_IO_BUF)
+		    wsi->u.ws.rx_ubuf_head != wsi->context->pt_serv_buf_size)
 			break;
 		else
 			if (wsi->protocol->rx_buffer_size &&
@@ -1517,7 +1516,7 @@ lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf,
 	if (wsi->protocol->rx_buffer_size)
 		buffer_size = wsi->protocol->rx_buffer_size;
 	else
-		buffer_size = LWS_MAX_SOCKET_IO_BUF;
+		buffer_size = wsi->context->pt_serv_buf_size;
 	avail = buffer_size - wsi->u.ws.rx_ubuf_head;
 
 	/* do not consume more than we should */
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index c6998aa100bc96db5b6bb679dcf2e0a6f9b53f94..ab06b9d40c85564350c8f1b2b809275f47909458 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -352,7 +352,6 @@ extern "C" {
 #endif
 
 #define MAX_WEBSOCKET_04_KEY_LEN 128
-#define LWS_MAX_SOCKET_IO_BUF 4096
 
 #ifndef SYSTEM_RANDOM_FILEPATH
 #define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
@@ -742,6 +741,7 @@ struct lws_context {
 	unsigned int options;
 	unsigned int fd_limit_per_thread;
 	unsigned int timeout_secs;
+	unsigned int pt_serv_buf_size;
 
 	/*
 	 * set to the Thread ID that's doing the service loop just before entry
diff --git a/lib/server-handshake.c b/lib/server-handshake.c
index 1d0be11bfde9ce37391f9cc059f14101e9701a14..ef7c5cec4e62eaef1d0bd4a2652beff94700d344 100644
--- a/lib/server-handshake.c
+++ b/lib/server-handshake.c
@@ -48,7 +48,7 @@ lws_extension_server_handshake(struct lws *wsi, char **p)
 	 * and go through them
 	 */
 
-	if (lws_hdr_copy(wsi, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF,
+	if (lws_hdr_copy(wsi, (char *)pt->serv_buf, context->pt_serv_buf_size,
 			 WSI_TOKEN_EXTENSIONS) < 0)
 		return 1;
 
@@ -191,7 +191,7 @@ handshake_0405(struct lws_context *context, struct lws *wsi)
 	lws_SHA1(pt->serv_buf, n, hash);
 
 	accept_len = lws_b64_encode_string((char *)hash, 20, (char *)pt->serv_buf,
-					   LWS_MAX_SOCKET_IO_BUF);
+			context->pt_serv_buf_size);
 	if (accept_len < 0) {
 		lwsl_warn("Base64 encoded hash too long\n");
 		goto bail;
diff --git a/lib/server.c b/lib/server.c
index c109585fe14e4eb238f40cb24fba758196eead88..52991d0711c653fbc62c1f0a026fc178aed537f4 100644
--- a/lib/server.c
+++ b/lib/server.c
@@ -1134,7 +1134,7 @@ upgrade_ws:
 
 		n = wsi->protocol->rx_buffer_size;
 		if (!n)
-			n = LWS_MAX_SOCKET_IO_BUF;
+			n = context->pt_serv_buf_size;
 		n += LWS_PRE;
 		wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
 		if (!wsi->u.ws.rx_ubuf) {
@@ -1612,7 +1612,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
 		}
 
 		len = lws_ssl_capable_read(wsi, pt->serv_buf,
-					   LWS_MAX_SOCKET_IO_BUF);
+					   context->pt_serv_buf_size);
 		lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len);
 		switch (len) {
 		case 0:
@@ -1781,7 +1781,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
 	char cache_control[50], *cc = "no-store";
 	unsigned char *response = pt->serv_buf + LWS_PRE;
 	unsigned char *p = response;
-	unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE;
+	unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
 	int ret = 0, cclen = 8;
 
 	wsi->u.http.fd = lws_plat_file_open(wsi, file, &wsi->u.http.filelen,
diff --git a/lib/service.c b/lib/service.c
index f6ad73a2f7b07a7630b9c223372c25a745031ae3..8ef82155f547f316adb39e48298b1306890f6350 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -893,7 +893,7 @@ read:
 			if (wsi->mode != LWSCM_HTTP_CLIENT_ACCEPTED) {
 				eff_buf.token_len = lws_ssl_capable_read(wsi,
 					pt->serv_buf, pending ? pending :
-							LWS_MAX_SOCKET_IO_BUF);
+					context->pt_serv_buf_size);
 				switch (eff_buf.token_len) {
 				case 0:
 					lwsl_info("%s: zero length read\n", __func__);
@@ -989,8 +989,8 @@ drain:
 
 		pending = lws_ssl_pending(wsi);
 		if (pending) {
-			pending = pending > LWS_MAX_SOCKET_IO_BUF ?
-					LWS_MAX_SOCKET_IO_BUF : pending;
+			pending = pending > context->pt_serv_buf_size ?
+					context->pt_serv_buf_size : pending;
 			goto read;
 		}
 
diff --git a/lib/ssl.c b/lib/ssl.c
index 685584e00a882bbdce450fc2c7eaccb580b63f9a..6b2e575df49c334637b244ac70f448410ae4a0ac 100644
--- a/lib/ssl.c
+++ b/lib/ssl.c
@@ -537,7 +537,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
 
 		lws_latency_pre(context, wsi);
 
-		n = recv(wsi->sock, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF,
+		n = recv(wsi->sock, (char *)pt->serv_buf, context->pt_serv_buf_size,
 			 MSG_PEEK);
 
 		/*