Troubleshooting guide · dns-ssl · Published 2026-08-16 · 3 min read
TLS handshake failures troubleshooting
Troubleshoot TLS handshake failures by layer: protocol, cipher, certificate, and server configuration, with browser and log evidence.
- ·Read the symptom
- ·Diagnosis by layer
- ·Involve professionals
Read the symptom before touching anything
A TLS handshake failure is any error between the moment the browser chooses the address and the moment encrypted bytes start flowing. The browser text already partitions the cause space:
| Symptom | Layer the error lives in |
|---|---|
ERR_SSL_PROTOCOL_ERROR (Chrome) / SSL_ERROR_PROTOCOL_VERSION_ALERT (Firefox) | Protocol version mismatch |
ERR_SSL_VERSION_OR_CIPHER_MISMATCH / ssl_error_no_cypher_overlap | Cipher suite overlap |
SSL_ERROR_SSL with a certificate warning | Certificate/trust chain |
Handshake that hangs and then timeout | Network path (or server overloaded) |
The same failure can be told apart in one sentence: protocol errors say "we do not share a TLS version", cipher errors say "we do not share a cipher", certificate errors say "we share a cipher but the identity does not check out", and timeouts say "neither side showed up on time".
Diagnosis by layer
1. Protocol version
Check which TLS versions the server actually speaks:
openssl s_client -connect example.com:443 -tls1_2
If the server only exposes TLS 1.0 or 1.1 (or rejects -tls1_2), every modern browser fails at handshake because it offers no shared version. The fix lives in the web server TLS config, which is covered in the SSL error and the handshake basics articles.
2. Cipher suite
When the version works but ciphers do not, the server advertised suites the client cannot use (for example, only suites restricted by export-grade policy). List the server's offered ciphers:
openssl s_client -connect example.com:443
Enable a modern common suite (TLS_AES_256_GCM_SHA384 and friends) and remove the legacy set. If the server is behind Cloudflare, see the Cloudflare 525 article, which is the same mismatch from the edge side.
3. Certificate
Read the served certificate and chain:
openssl s_client -connect example.com:443 -showcerts
Check the three failure classes: expiry (covered by the certificate errors article), missing intermediate chain (chain incomplete, the peer cannot validate), and hostname mismatch (certificate valid but for another name, common after a domain change).
4. Server overload
A TLS timeout with no error text, coinciding with load, is the MySQL-gone-away equivalent at the socket layer: the origin trims keepalive connections the CDN relies on. Check connection limits (netstat/ss on the server after reproducing on :443 only), and consult the timeout article for the session trimming fixes that also stop handshake timeouts.
Involved fixes (when the log is authoritative)
When the browser text is ambiguous, read the server log line that records the alert. nginx writes SSL_do_handshake() failed, which names the exact alert code; ssl_errors from the daemon line up with the ciphers/version test above. If the error appears for some visitors and not others, it usually points at clients stuck on an old OS or Java runtime, not at the server.
When to involve a professional
You have largely solved it when the three tests above pinpoint a layer. There are two cases worth hiring out: a corporate reverse-proxy chain (load balancer, WAF, CDN, and origin each hold a handshake hop, and the failing hop is invisible mid-chain), and a certificate chain that resists repair because the origin refuses to bundle intermediates. On Cloudflare the edge shows the chain problem before origin traffic, so the 525 article is the quicker route there.