A TLS handshake failure is a negotiation breakdown, not a single error
· tls · ssl · handshake · openssl · certificates
tlssslhandshakeopensslcertificatesA TLS handshake failure means the client and server could not finish negotiating a secure session before any application data was sent. It is not one error — it is a family of them. The handshake breaks when the two sides share no common protocol version, no common cipher suite or curve, when the server presents a certificate the client rejects (expired, not-yet-valid, untrusted, wrong name), when SNI is missing on a multi-host server, or when something in the middle interferes with the connection. The fix depends entirely on which step actually failed, so the first job is to find that step.
Protocol and cipher mismatch
Modern servers commonly disable TLS 1.0 and 1.1, and many now require TLS 1.2 or 1.3. If the client is old enough to only speak TLS 1.0/1.1, the ClientHello offers nothing the server accepts and the handshake aborts immediately. The mirror case is a cipher or curve mismatch: the client and server each advertise a list, and if the intersection is empty — for example a server pinned to a single modern AEAD suite talking to a client that only offers legacy CBC ciphers, or an ECDHE key exchange where the two sides share no supported elliptic curve — negotiation fails.
You can confirm by pinning a version and watching where it breaks:
openssl s_client -connect example.com:443 -servername example.com -tls1_2
openssl s_client -connect example.com:443 -servername example.com -tls1_3
If one version connects and another fails, you have a protocol mismatch. If every version fails with no shared cipher or a handshake alert, it is a cipher or curve problem on one side.
Certificate problems
The handshake also fails when the server's certificate is rejected during verification. The common cases are: the certificate has expired or is not yet valid (the notBefore date is in the future), it is signed by a CA the client does not trust, the names in the certificate do not cover the host requested, or the chain is incomplete so the client cannot build a path to a trusted root. A client clock that is badly wrong produces the same symptom — a valid certificate looks expired or not-yet-valid because the machine's idea of "now" is off.
openssl s_client -connect example.com:443 -servername example.com
Read the Verify return code line at the bottom. 0 (ok) means the chain verified; anything else — certificate has expired, unable to get local issuer certificate, self-signed certificate in certificate chain — names the exact verification fault.
SNI, proxies, and how to diagnose
On servers that host many sites on one IP, the certificate is chosen by SNI — the hostname the client sends in the ClientHello. Omit it and the server returns its default certificate, which usually fails the name check. That is why -servername matters: it sets SNI explicitly and reproduces what a browser does. An intercepting proxy, firewall, or corporate TLS-inspection appliance is the other frequent culprit: it terminates the connection and presents its own certificate, or it drops handshakes for protocols it does not understand, so the failure you see is the middlebox's, not the origin's.
Work the diagnosis in order: run openssl s_client with -servername first, read the Verify return code, then pin TLS versions to isolate protocol versus cipher. If the certificate chain is the fault, an incomplete chain is one of the most common and most fixable causes.
Further reading
- TLS certificate guide: reading what your certificate actually says
- Incomplete certificate chain: why some clients fail and others don't
- RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3
- RFC 6066 — TLS Extensions, including Server Name Indication (SNI)