diff --git a/changelog b/changelog
index 92035c98873a1f185d68eb9f21e77c12dc637462..b2ef533b03464b9a770cea7e45314f272138ee26 100644
--- a/changelog
+++ b/changelog
@@ -72,6 +72,10 @@ with systemd
 6) test server html is updated with tabs and a new live server monitoring
 feature.  Input sanitization added to the js.
 
+7) client connections attempted when no ah is free no longer fail, they are
+just deferred until an ah becomes available.
+
+
 User API additions
 ------------------
 
diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index 264cca98ec7f1e7662bd638bd342286a051bd00c..aaeb335d4e642d933c60c8c1f5e850294071cf6f 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -26,7 +26,7 @@ lws_client_connect_2(struct lws *wsi)
 			"CONNECT %s:%u HTTP/1.0\x0d\x0a"
 			"User-agent: libwebsockets\x0d\x0a",
 			lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
-			wsi->u.hdr.ah->c_port);
+			wsi->u.hdr.c_port);
 
 		if (context->proxy_basic_auth_token[0])
 			plen += sprintf((char *)pt->serv_buf + plen,
@@ -49,10 +49,10 @@ lws_client_connect_2(struct lws *wsi)
 #ifdef LWS_USE_IPV6
 		if (LWS_IPV6_ENABLED(context)) {
 			memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
-			server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
+			server_addr6.sin6_port = htons(wsi->u.hdr.c_port);
 		} else
 #endif
-			server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
+			server_addr4.sin_port = htons(wsi->u.hdr.c_port);
 	}
 
 	/*
@@ -258,7 +258,7 @@ lws_client_connect_2(struct lws *wsi)
 		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
 					  context->http_proxy_address))
 			goto failed;
-		wsi->u.hdr.ah->c_port = context->http_proxy_port;
+		wsi->u.hdr.c_port = context->http_proxy_port;
 
 		n = send(wsi->sock, (char *)pt->serv_buf, plen,
 			 MSG_NOSIGNAL);
@@ -358,7 +358,7 @@ lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const
 	wsi->state = LWSS_CLIENT_UNCONNECTED;
 	wsi->protocol = NULL;
 	wsi->pending_timeout = NO_PENDING_TIMEOUT;
-	wsi->u.hdr.ah->c_port = port;
+	wsi->u.hdr.c_port = port;
 
 	return lws_client_connect_2(wsi);
 }
@@ -382,10 +382,16 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 		goto bail;
 
 	wsi->context = i->context;
+	/* assert the mode and union status (hdr) clearly */
+	lws_union_transition(wsi, LWSCM_HTTP_SERVING);
 	wsi->sock = LWS_SOCK_INVALID;
 
-	/* -1 means just use latest supported */
+	/* 1) fill up the wsi with stuff from the connect_info as far as it
+	 * can go.  It's because not only is our connection async, we might
+	 * not even be able to get ahold of an ah at this point.
+	 */
 
+	/* -1 means just use latest supported */
 	if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
 		v = i->ietf_version_or_minus_one;
 
@@ -395,6 +401,13 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 	wsi->protocol = NULL;
 	wsi->pending_timeout = NO_PENDING_TIMEOUT;
 	wsi->position_in_fds_table = -1;
+	wsi->u.hdr.c_port = i->port;
+
+	wsi->protocol = &i->context->protocols[0];
+	if (wsi && !wsi->user_space && i->userdata) {
+		wsi->user_space_externally_allocated = 1;
+		wsi->user_space = i->userdata;
+	}
 
 #ifdef LWS_OPENSSL_SUPPORT
 	wsi->use_ssl = i->ssl_connection;
@@ -405,42 +418,93 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 	}
 #endif
 
-	if (lws_header_table_attach(wsi, 0))
+	/* 2) stash the things from connect_info that we can't process without
+	 * an ah.  Because if no ah, we will go on the ah waiting list and
+	 * process those things later (after the connect_info and maybe the
+	 * things pointed to have gone out of scope.
+	 */
+
+	wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
+	if (!wsi->u.hdr.stash) {
+		lwsl_err("%s: OOM\n", __func__);
 		goto bail;
+	}
+
+	wsi->u.hdr.stash->origin[0] = '\0';
+	wsi->u.hdr.stash->protocol[0] = '\0';
+
+	strncpy(wsi->u.hdr.stash->address, i->address,
+		sizeof(wsi->u.hdr.stash->address) - 1);
+	strncpy(wsi->u.hdr.stash->path, i->path,
+		sizeof(wsi->u.hdr.stash->path) - 1);
+	strncpy(wsi->u.hdr.stash->host, i->host,
+		sizeof(wsi->u.hdr.stash->host) - 1);
+	if (i->origin)
+		strncpy(wsi->u.hdr.stash->origin, i->origin,
+			sizeof(wsi->u.hdr.stash->origin) - 1);
+	if (i->protocol)
+		strncpy(wsi->u.hdr.stash->protocol, i->protocol,
+			sizeof(wsi->u.hdr.stash->protocol) - 1);
+
+	wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
+	wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
+	wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
+	wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
+	wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
+
+	/* if we went on the waiting list, no probs just return the wsi
+	 * when we get the ah, now or later, he will call
+	 * lws_client_connect_via_info2() below
+	 */
+	if (lws_header_table_attach(wsi, 0))
+		lwsl_debug("%s: went on ah wait list\n", __func__);
+
+	return wsi;
+
+bail:
+	lws_free(wsi);
+
+	return NULL;
+}
+
+struct lws *
+lws_client_connect_via_info2(struct lws *wsi)
+{
+	struct client_info_stash *stash = wsi->u.hdr.stash;
+
+	if (!stash)
+		return wsi;
 
 	/*
 	 * we're not necessarily in a position to action these right away,
 	 * stash them... we only need during connect phase so u.hdr is fine
 	 */
-	wsi->u.hdr.ah->c_port = i->port;
-	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, i->address))
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+				  stash->address))
 		goto bail1;
 
 	/* these only need u.hdr lifetime as well */
 
-	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, i->path))
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
 		goto bail1;
 
-	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, i->host))
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
 		goto bail1;
 
-	if (i->origin)
-		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, i->origin))
+	if (stash->origin[0])
+		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
+					  stash->origin))
 			goto bail1;
 	/*
 	 * this is a list of protocols we tell the server we're okay with
 	 * stash it for later when we compare server response with it
 	 */
-	if (i->protocol)
+	if (stash->protocol[0])
 		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
-					  i->protocol))
+					  stash->protocol))
 			goto bail1;
 
-	wsi->protocol = &i->context->protocols[0];
-	if (wsi && !wsi->user_space && i->userdata) {
-		wsi->user_space_externally_allocated = 1;
-		wsi->user_space = i->userdata;
-	}
+	lws_free_set_NULL(wsi->u.hdr.stash);
 
 	/*
 	 * Check with each extension if it is able to route and proxy this
@@ -449,9 +513,10 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 	 * connection.
 	 */
 
-	if (lws_ext_cb_all_exts(i->context, wsi,
-			LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
-						     (void *)i->address, i->port) > 0) {
+	if (lws_ext_cb_all_exts(wsi->context, wsi,
+				LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
+				(void *)stash->address,
+				wsi->u.hdr.c_port) > 0) {
 		lwsl_client("lws_client_connect: ext handling conn\n");
 
 		lws_set_timeout(wsi,
@@ -462,17 +527,12 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 		return wsi;
 	}
 	lwsl_client("lws_client_connect: direct conn\n");
-
 	wsi->context->count_wsi_allocated++;
 
 	return lws_client_connect_2(wsi);
 
 bail1:
-	/* we're closing, losing some rx is OK */
-	wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
-	lws_header_table_detach(wsi, 0);
-bail:
-	lws_free(wsi);
+	lws_free_set_NULL(wsi->u.hdr.stash);
 
 	return NULL;
 }
diff --git a/lib/parsers.c b/lib/parsers.c
index cb0254143928ab202a46e50abe3f61d292c41bfe..fab799ef1528d54305aee47d8218fb11ab7d05dc 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -185,6 +185,11 @@ reset:
 	lws_header_table_reset(wsi, autoservice);
 	time(&wsi->u.hdr.ah->assigned);
 
+#ifndef LWS_NO_CLIENT
+	if (wsi->state == LWSS_CLIENT_UNCONNECTED)
+		lws_client_connect_via_info2(wsi);
+#endif
+
 	return 0;
 
 bail:
@@ -293,6 +298,11 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
 	wsi->u.hdr.ah_wait_list = NULL;
 	pt->ah_wait_list_length--;
 
+#ifndef LWS_NO_CLIENT
+	if (wsi->state == LWSS_CLIENT_UNCONNECTED)
+		lws_client_connect_via_info2(wsi);
+#endif
+
 	assert(!!pt->ah_wait_list_length == !!(int)(long)pt->ah_wait_list);
 bail:
 	lws_pt_unlock(pt);
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index d7a9389c11ab1127a5805a574e7d6ccb9ea95542..8fe072df98372e98b506fc12f565c4c651970d88 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -359,7 +359,7 @@ enum lws_connection_states {
 	LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS,
 	LWSS_HTTP2_ESTABLISHED,
 
-	LWSS_CGI
+	LWSS_CGI,
 };
 
 enum http_version {
@@ -517,7 +517,6 @@ struct allocated_headers {
 
 #ifndef LWS_NO_CLIENT
 	char initial_handshake_hash_base64[30];
-	unsigned short c_port;
 #endif
 
 	unsigned short pos;
@@ -788,10 +787,37 @@ enum uri_esc_states {
  * used interchangeably to access the same data
  */
 
+struct _lws_header_related {
+	/* MUST be first in struct */
+	struct allocated_headers *ah;
+	struct lws *ah_wait_list;
+	unsigned char *preamble_rx;
+#ifndef LWS_NO_CLIENT
+	struct client_info_stash *stash;
+#endif
+	unsigned int preamble_rx_len;
+	enum uri_path_states ups;
+	enum uri_esc_states ues;
+	short lextable_pos;
+	unsigned short current_token_limit;
+#ifndef LWS_NO_CLIENT
+	unsigned short c_port;
+#endif
+	char esc_stash;
+	char post_literal_equal;
+	unsigned char parser_state; /* enum lws_token_indexes */
+	char redirects;
+};
+
 struct _lws_http_mode_related {
 	/* MUST be first in struct */
 	struct allocated_headers *ah; /* mirroring  _lws_header_related */
 	struct lws *ah_wait_list;
+	unsigned char *preamble_rx;
+#ifndef LWS_NO_CLIENT
+	struct client_info_stash *stash;
+#endif
+	unsigned int preamble_rx_len;
 	struct lws *new_wsi_list;
 	unsigned long filepos;
 	unsigned long filelen;
@@ -950,21 +976,16 @@ struct _lws_http2_related {
 
 #endif
 
-struct _lws_header_related {
-	/* MUST be first in struct */
-	struct allocated_headers *ah;
-	struct lws *ah_wait_list;
-	unsigned char *preamble_rx;
-	unsigned int preamble_rx_len;
-	enum uri_path_states ups;
-	enum uri_esc_states ues;
-	short lextable_pos;
-	unsigned short current_token_limit;
-	char esc_stash;
-	char post_literal_equal;
-	unsigned char parser_state; /* enum lws_token_indexes */
-	char redirects;
+#ifndef LWS_NO_CLIENT
+struct client_info_stash {
+	char address[256];
+	char path[1024];
+	char host[256];
+	char origin[256];
+	char protocol[256];
 };
+#endif
+
 
 struct _lws_websocket_related {
 	/* cheapest way to deal with ah overlap with ws union transition */
@@ -1212,6 +1233,9 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt);
 LWS_EXTERN int
 lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
 
+LWS_EXTERN struct lws *
+lws_client_connect_via_info2(struct lws *wsi);
+
 /*
  * EXTENSIONS
  */