Diagnosing handshake failures, certificate errors and latency at scale requires knowing what each message does.
A TLS 1.3 handshake fits in one round trip.
ClientHello carries: supported cipher suites (AEAD ciphers like AES-GCM or ChaCha20-Poly1305), a key share (an ephemeral elliptic-curve Diffie-Hellman public key, commonly X25519, increasingly combined with a post-quantum ML-KEM key), SNI (the hostname, so one IP can serve many certificates) and ALPN (the application protocols it speaks, such as h2 and http/1.1).
ServerHello picks the parameters and sends its own key share. Both sides now compute the same shared secret, and everything after is encrypted: the server's certificate chain, a CertificateVerify signature proving it holds the private key, and Finished messages that authenticate the whole transcript.
The client validates the chain: leaf certificate for this hostname (Subject Alternative Name), intermediates, up to a root in its trust store, all within validity dates and not revoked. A missing intermediate is a classic misconfiguration: it works in some browsers that cache intermediates and fails elsewhere.
Forward secrecy: because key shares are ephemeral, stealing the server's private key later doesn't decrypt recorded traffic.
Resumption: the server issues a session ticket; a returning client uses a pre-shared key to skip certificate work. With 0-RTT early data it can send its first request immediately, but that data can be replayed by an attacker, so servers should accept only safe, idempotent requests in early data.
SNI is still sent in clear text; Encrypted Client Hello (ECH) hides it, using keys published in DNS HTTPS records.
Example
# See the negotiated protocol, cipher, ALPN and certificate chain
$ openssl s_client -connect example.com:443 -servername example.com \
-alpn h2,http/1.1 </dev/null 2>/dev/null \
| grep -E "^(New|ALPN|Server Temp Key|Verify return)"
Server Temp Key: X25519, 253 bits
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
ALPN protocol: h2
Verify return code: 0 (ok)
# Print each certificate in the chain the server sends
$ openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
| grep -E "^ *[0-9] s:|i:"Remember
- TLS 1.3 completes in 1 RTT: ClientHello with key share, ServerHello, encrypted certificate and Finished
- SNI selects the certificate; ALPN negotiates h2 or http/1.1
- Ephemeral key exchange gives forward secrecy
- 0-RTT data can be replayed: allow only idempotent requests
Watch out for
- Serving only the leaf certificate without intermediates, which fails on clients that haven't cached them.