# TLS Handshake

> The TLS handshake negotiates keys and authenticates the server before HTTP data flows. See the TLS 1.3 round trip, ALPN, session resumption and 0-RTT risks.

Source: https://howhttpworks.com/glossary/tls-handshake
Last reviewed: 2026-10-04

> **TL;DR:** The TLS handshake is the exchange before any HTTP bytes flow: agree on parameters, verify the server certificate, and derive shared keys. TLS 1.3 does it in one round trip.

The TLS handshake is the opening exchange in which a client and server negotiate a protocol version and cipher suite, authenticate the server with an X.509 certificate, and derive the symmetric keys that protect the rest of the connection. For HTTPS, it runs after the TCP handshake and before the first HTTP request.

## What the messages carry (TLS 1.3)

1. **ClientHello:** supported versions and ciphers, a key share, the server name (see [SNI](https://howhttpworks.com/glossary/sni)) and ALPN protocols such as `h2` and `http/1.1`.
2. **ServerHello and the rest of the server flight:** chosen parameters and key share; everything after this is encrypted, including the certificate and a `Finished` message.
3. **Client Finished:** the client can now send HTTP in the same flight.

Abridged `curl -v` output (wording differs between curl and TLS library versions):

```text
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* ALPN: server accepted h2
```

## Non-obvious facts

- **TCP plus TLS 1.3 is two round trips before the request.** One for TCP, one for TLS. TLS 1.2 made it three. This is why connection reuse ([keep-alive](https://howhttpworks.com/glossary/keep-alive)) matters so much for latency.
- **Resumption skips most of the work.** A returning client can present a session ticket and resume without a full key exchange.
- **0-RTT (early data) can be replayed.** The server cannot tell a replayed early request from the original. RFC 8470 lets a server reply `425 Too Early`; in practice only idempotent requests belong in early data.
- **ALPN decides HTTP version.** If the server does not offer `h2`, the connection falls back to HTTP/1.1; there is no separate upgrade step.
- **Handshake failures appear as TLS alerts, not HTTP statuses.** There is no HTTP response yet, which is why browsers show [`ERR_SSL_PROTOCOL_ERROR`](https://howhttpworks.com/debug/err-ssl-protocol-error) or a certificate error page rather than a status code. Behind Cloudflare, you may instead see a 525 when the CDN-to-origin handshake fails.

## Go deeper

- [HTTPS and TLS guide](https://howhttpworks.com/guides/https-and-tls)
- [Strict-Transport-Security](https://howhttpworks.com/headers/strict-transport-security)
- [425 Too Early](https://howhttpworks.com/status-codes/425)
- [Certificate common name error](https://howhttpworks.com/debug/err-cert-common-name-invalid)
- [525 SSL Handshake Failed](https://howhttpworks.com/status-codes/525)
