HTTPS and Keep-Alive Connections

As we explore network performance on the “real-world web”, one bad pattern in particular keeps recurring, and it’s not something that our many IE9 Networking Performance Improvements alone will resolve.

The bad pattern is the use of Connection: close semantics for HTTPS connections. In this bad pattern, a website allows only a single request and response on every HTTPS connection before closing the connection.

Defeating HTTP/1.1’s default Keep-Alive behavior is a bad practice for regular HTTP connections but it’s far worse for HTTPS connections because the initial setup costs of a HTTPS connection are far higher than a regular HTTP connection. Not only does the browser pay the performance penalty of setting up a new TCP/IP connection, including the handshake and initial congestion window sizing, but the request’s progress is also penalized by the time required to complete the HTTPS handshake used to secure the connection.

To do all of that work and then only use it for one HTTP request and response is a terrible waste of resources-- it's like paving a highway, allowing a single car to drive down it, and then dynamiting the road after it passes. You then need to pave a new highway for the next car, only to subsequently blow it up, and so on. This bad pattern can dramatically slow down the loading of the page and increase the load on your server.

Browsers have no choice but to close the connection when directed by the server; it would be a violation of the standard (and almost certainly wouldn’t work) to try to ignore the server’s directive to close the connection.

A while ago, I saw one site that was particularly bad in this regard—it was a shopping site that showed many product thumbnails on every page; the page included 200 thumbnail images, each delivered over HTTPS, and each from a server in Asia that closed the connection after every single response. While browsers work their hardest to load this page, performing multiple connections in parallel, each page on the site took several minutes to load. Using Fiddler to simulate exactly the same site, but allowing connection reuse, the site’s pages would load in about 15 seconds. I haven’t been back to that site since (they may not be in business any longer) but the problem can even be seen on “big” sites used by millions of people every day.

You can observe Connection Reuse with Fiddler’s Timeline tab. Right-click on the tab and change the view to Server PortMap and then look to see how many connections are reused.

On a site that makes good use of Keep-Alive, you’ll see that many connections are reused for multiple requests.


This site only has more than 6 lines (the connections-per-host limit) because it “shards” its requests across a number of related domains.

In contrast, here’s a site which does not allow connection reuse:


The chart shows that each request is made on a new connection, and a small red-x after each transfer indicates that the server is using the Connection: close pattern. Only a few connections are reused (near the bottom of the trace) as these are cross-domain requests to a server that is configured for better performance.

Overall, loading of the site is delayed due to the overhead in establishing HTTPS connections. The performance penalty will be even larger for clients that have longer round-trip times (e.g. on 3G connections, or more geographically distant users).

Our team did a bit of research into this bad pattern, and we found two common origins of the bad pattern.

In the first, a thoughtful web developer or operations team reasons: “Hey, HTTPS connections are expensive to maintain on the server. Let’s be sure to tear those down as soon as possible to free up the server to accept new connections.”  That, of course, completely misses the point that if the server wasn’t tearing down the connections, the server would be under significantly lighter load to begin with! Sites that were deliberately written with this bad pattern load slowly in all browsers.

We also found another root cause—ancient advice for the configuration of Apache+OpenSSL. Prior to IE6, ancient and unpatched versions of IE sometimes encountered connection failures when interacting with HTTPS servers when Keep-Alive is used. That problem was fixed nearly a decade ago, but outdated 1999-era configuration advice continues to harm performance for unaware server administrators:
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
SSLOptions +ExportCertData +StrictRequire
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
SetEnvIf Request_URI \.gif$ gif-image
CustomLog /var/log/httpd/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" env=!gif-image

Four years ago, there was a public call to update the guidance to reflect the fact that users of more modern browsers were paying an unneeded performance penalty. Finally, in June 2010, the default guidance was changed in recognition of the fact that the problem never affected IE6 and later:

BrowserMatch ".*MSIE [1-5].*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0

Unfortunately, many major Apache installations still haven’t been updated with even this guidance. Also, alert readers will spot a very obvious problem with the “new” regular expression.

In the expression above, any IE version that starts with “1” will be treated as outdated and served connection slowly without Keep-Alive. Internet Explorer 1.0 didn’t even support SSL at all (SSL was added in 2.0), but worse, this loosely-written regular expression will also match future MSIE 10.0, MSIE 11.0, MSIE 12.0 (etc) user-agent strings. Hence, Apache hosts will one day find that the newest browsers are forced into the “slow” lane!

At the very least, Apache hosts should update their regular expression to this:

BrowserMatch ".*MSIE [2-5]\..*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0

…but ultimately, they should probably remove this hack altogether. The ancient Internet Explorer 6’s marketshare is in decline, and there’s almost never any business reason to try to accommodate even older browsers.

Thanks for your help in building a faster web!

-Eric Lawrence

Comments (20)
  1. JM says:

    Opera 10.0+ has "Opera/9.80" in its user agent string. This would be acceptable solution for Internet Explorer, too.

  2. Yes, lying to accommodate buggy software has a long history, and its own set of tradeoffs. However, the number of servers which make this mistake for all versions far outnumbers those using the new-but-still-bad guidance published last year.

  3. hAl says:

    How is this behaviour by websites and webservers going to change?

  4. @Hal: Websites can update their buggy Apache configuration files and will immediately start loading more quickly.

  5. Eyal says:

    We have a load balancer from f5 which, when using compression and chunked transfers (ie when we flush the response before it ends) it automatically adds a connection-close header.

    Also, sometimes adds this header as described here:…/avoiding-connection-close-when-returning-a-304-not-modified-status-code-in-aspnet-part-2

  6. Drit says:

    Eric this is a great article on the impact of Connection:Close ! We observed a similar issue on a major website and posted an article on the same topic at:…/relying_on_web_performance_monitoring_to_discover_release_problems

  7. Simon Lieschke says:

    Various resources (see end) also include the following directives for later versions of Internet Explorer:

    BrowserMatch "MSIE [6-9]" ssl-unclean-shutdown

    Do you any more details on this? Is it still required for Internet Explorer 10?…/dear-apache-software-foundation-fix-the-msie-ssl-keepalive-settings…/what-must-i-do-to-make-content-such-as-images-served-over-https-be-cached-client…/General+Apache+Configuration+Notes

  8. Simon Lieschke says:

    Sorry, that was a brain explosion on the previous comment. Internet Explorer 10 doesn't exist yet. Nonetheless do you know why people are specifying ssl-unclean-shutdown for later versions of Internet Explorer?

    My concern, like what you pointed out with the regex people have been using in your post, is that a similar problem could exist when Internet Explorer 10 is released if ssl-unclean-shutdown is still required for that browser version – the regex won't match and ssl-unclean-shutdown won't be applied.

    Of course if Internet Explorer 10 doesn't need ssl-unclean-shutdown then it will all be conveniently moot 😉

  9. Markus Leptien says:

    Hi Eric!

    I saw some really weird IE behaviour in case you shard CSS files and CSS images across different domains when using SSL. Any chance you have an insight on this?

    I wrote some more analysis about this here:…/domain-sharding-and-ssl

    Kind regards,


  10. @Markus: Thanks for the note and writeup. Yes, we actually saw this a few months ago and we know what causes it; basically, you have to have #cross-origin HTTPS references > max-connections-per-server and you can hit an unnecessary client closure issue. We're looking at addressing this for a future release of IE. Thx.

  11. Adam Rand says:

    I'm with Simon, seeing "ssl-unclean-shutdown" applied to IE.  Anyone have more insight on which versions of IE that should apply to?

  12. KS says:

    It seems that some firewalls (in this case a McAfee UTM appliance) also terminate keep-alive sessions regularly. A few weeks ago while troubleshooting a caching issue I recognized that all connections from my servers had connection:close although they should have been keep-alive connections. And I couldn't get it go away. Drove me nearly crazy. Then an hour or two later I accidentally found out that this was happening only when retrieving the pages here, but not when trying from other locations. I haven't yet found out why it happens. Interestingly, the https connections can stay on keep-alive, it's only the http connections that suffer from it.

  13. KS says:

    @Adam: you can safely remove the complete SetEnvIF. I have it in none of my virtual hosts and the https ones work just fine with all versions of IE (versions before 6 do not count).

  14. ES says:

    Going with KS here.

    Reading through the post, I can only conclude that browsers that aren't supported at all anymore need to have this configuration line in Apache.

    If the formal statement of a company would be to not support IE versions older than 6, one can immediately start with removing the line from the Apache config file (and restart Apache service after modifying the config).

    BTW, very happy with this post. As I was looking through our Apache config, I found this line which alarmed me. I already changed it to only use ssl-unclean-shutdown as was posted on other sites, but this confirms my thoughts that even the complete line can be removed.

  15. Shmuel Krakower says:

    Hi Erik,

    Is it possible that IE (8) is ignoring http keep-alive timeout=5 header?

    We have a web application which sets this timeout to 5 seconds (which is obvious bad for performance) and we notice bad performance when working with FireFox (it follows the timeout directive and close the connection, so each action on the application needs a DNS resolve + TCP new connection) but with IE we see that it perform much faster becuase it doesn't look for the DNS and it uses the same connection.

  16. EricLaw [MSFT] says:

    @Shmuel: WinINET (and thus Internet Explorer) has never supported the non-standard timeout attribute on the Connection header, a proprietary feature that Firefox inherited from its Netscape roots. If the server wishes to close a keep-alive connection, it can do so whenever it wants.

    (FWIW, even Firefox will not typically need to re-resolve the hostname in DNS, even if it's forced to close a keep-alive connection.)

  17. Siddharth says:

    are there any similar settings which can be done in IIS 7, we have similar problem in our sharepoint site, all css/js/images are loading grudally in subsequent page refresh… ?

  18. @Siddharth: Unless you've done something very strange, IIS will never close connections like this. You might consider capturing a SAZ File with Fiddler and asking your question in the Fiddler Discussion group:

  19. shahid Ahmed says:

    HTTP/1.1 servers default to the keep-alive setting of the Connection header. Why then do most browsers include Connection: keep-alive in their requests even when they know that the target server supports HTTP/1.1?

    [EricLaw] You're correct that this is unnecessary and it's probably done only for historical reasons. My understanding is that the .NET HTTP objects only send the header on the first request, a behavior that some developers found confusing.

  20. Keith says:

    Eric, thanks for the explanation – one thing I don't understand is that the CONNECT Request from IE9 (in my case) is HTTP 1.0 rather than HTTP 1.1. Is this because Apache told IE it would not accept 1.1 or does IE always use CONNECT HTTP 1.0?

    [EricLaw] For historical reasons, IE always uses HTTP/1.0 for its CONNECT tunnels. We pondered changing this a few times but couldn't think of any benefit to doing so. (Inside the tunnel, the secure traffic is HTTP/1.1 by default)

Comments are closed.

Skip to main content