On this page
What Is an SSL/TLS Handshake (and Why Does It Fail)?
TLS agrees on a version and cipher, verifies the certificate, and derives keys. Most failures are a name, a chain, or a protocol mismatch.
Quick answer
- A TLS handshake establishes an encrypted session: the client and server agree on a version and cipher suite, the server proves its identity with a certificate, and both derive symmetric keys.
- In TLS 1.3 the handshake takes one round trip and hides most of the negotiation; TLS 1.2 takes two.
- The most common failures are an expired certificate, a hostname mismatch, an incomplete chain, and a client or server that does not support a common protocol version.
- SNI lets one server present different certificates for different hostnames; a client that does not send it, or a server that ignores it, can receive the wrong certificate.
- The useful diagnostic is openssl s_client: it shows the chain, the negotiated protocol, and the verification error in one place.
What happens during a TLS handshake?
The client sends a ClientHello with the protocol versions it supports, a list of cipher suites, and optionally the server name. The server responds with its chosen parameters and its certificate chain. The client verifies the chain against trusted roots, checks the hostname, and both sides derive session keys so the rest of the connection is encrypted.
In TLS 1.3 most of this happens in one round trip, and the certificate is encrypted. In TLS 1.2 the negotiation is visible and takes two round trips. The handshake is also where the server proves it holds the private key for the certificate, which is why a certificate without its key cannot complete the connection.
Why does the handshake fail?
Four causes cover most failures. The certificate has expired. The certificate is valid but was issued for a different hostname. The chain is incomplete because the server does not send the intermediate certificate. Or the client and server cannot agree on a protocol version or cipher suite, which is common with old clients and hardened servers.
A fifth, quieter cause is SNI. If the server hosts several sites on one address, it selects a certificate by the name the client requests. A client that omits SNI, a proxy that strips it, or a backend that expects a different name can receive a certificate that does not match the requested host.
# Inspect the chain, protocol, and verification result in one go.
openssl s_client -connect example.com:443 -servername example.com -showcerts
# Common outputs:
# verify error:num=10:certificate has expired
# verify error:num=20:unable to get local issuer certificate (missing intermediate)
# verify error:num=62:hostname mismatch
# Check the certificate dates and SANs directly.
openssl x509 -in cert.pem -noout -dates -subject -ext subjectAltNameHow do you fix each cause?
For expiry, renew the certificate and automate renewal. For a hostname mismatch, issue a certificate that includes the exact name in its subject alternative names, including the www variant if users reach it. For an incomplete chain, concatenate the intermediate certificates behind the leaf in the server configuration.
For a protocol or cipher mismatch, check which versions the server allows and which the client supports, then widen the server’s range only as far as security policy permits. For SNI problems, ensure the proxy forwards the server name and that the backend has a certificate for it. After any change, retest with the same client that failed.
How is a handshake failure different from an HTTP error?
A handshake failure happens before HTTP. The client and server never agree on an encrypted channel, so no request is sent and no status code is returned. That is why the error appears as a connection error, a certificate warning, or a platform-specific code rather than a 4xx or 5xx response.
This distinction guides debugging: if you see an HTTP status, the handshake succeeded and the problem is above it. If you see a connection reset, a certificate error, or a timeout during connect, the handshake is the place to look. Checking the protocol layer first saves time on the wrong logs.
Where this bites vibecoders
Generated deployments often terminate TLS at the platform and then proxy to an app that also expects HTTPS, producing a handshake failure between the proxy and the origin. The browser sees a generic connection error, not an application error. Decide where TLS terminates, and make the internal hop match that decision.
Where AI coding assistants get this wrong
- Terminating TLS at the proxy and then proxying to an origin that only speaks HTTPS.
- Forgetting the intermediate certificate in a manual chain.
- Issuing a certificate for the apex domain but serving the www host.
- Hardening the server to TLS 1.3 while old clients still connect with 1.2.
- Assuming a certificate error is an application bug.
- Renewing manually with no monitoring before expiry.
Checklist
- Confirm where TLS terminates in the request path.
- Inspect the chain and verification result with openssl.
- Check certificate dates and subject alternative names.
- Send the full chain including intermediates.
- Confirm the proxy forwards SNI to the backend.
- Automate renewal and alert before expiry.
FAQ
Is SSL the same as TLS?
SSL is the older protocol; TLS is its successor. The industry still says SSL for certificates and handshakes, but the protocol in use is TLS. Modern clients have deprecated SSL versions entirely, so an SSL-only server will fail to negotiate with current browsers.
Why does the site work in one browser but fail in another?
Different clients support different protocol versions, cipher suites, and certificate validation rules. An old client may not support TLS 1.3 or a modern cipher; a strict client may reject a missing intermediate or a certificate with a weak signature. The handshake is where those differences show up.
What does unable to get local issuer certificate mean?
The client received a certificate but could not build a chain to a trusted root, usually because the server did not send the intermediate certificate. Browsers sometimes cache or fetch missing intermediates, which is why the site works in a browser but fails in curl or an API client.
Can a firewall cause a handshake failure?
Yes. A firewall or middlebox that inspects or blocks TLS can reset the connection during the handshake, and a proxy that terminates TLS may present a certificate the client does not trust. If the failure appears only on one network, suspect the path before the server configuration.
Related topics
- Cloudflare 525 and 526: How to Fix an SSL Handshake Failure
- 502 vs 503 vs 504: What’s the Difference?
- How to Add HTTPS to a Static Site
- What Is HSTS (and Why Your HTTPS Isn’t Enough)?
- What Is a Reverse Proxy?
- DNS Propagation: Why Your Domain Still Points Elsewhere
- Don’t Let Your Domain Expire: Monitoring Domain and Certificate Renewals