The TLS Handshake Explained: From ClientHello to Encrypted Data

TLS sets up an encrypted channel in a few round trips. The 1.2 and 1.3 handshakes, what each message does, and why TLS 1.3 is dramatically faster.

The TLS Handshake Explained: From ClientHello to Encrypted Data

Every HTTPS request starts with a TLS handshake — a brief negotiation in which the client and server agree on which cipher to use, exchange keys, and establish an encrypted tunnel. It happens in milliseconds and most developers never look at it. But understanding it is essential for diagnosing connection problems, optimizing latency, and reasoning about web security in general.

This post walks through the TLS handshake at a practical level: what TLS 1.2 looked like, what TLS 1.3 does differently, what each message contains, and how it all combines into the fast, secure connection you take for granted in 2026.

A Quick Refresher on TLS

TLS (Transport Layer Security) is the protocol that adds encryption, authentication, and integrity to TCP connections. It’s the successor to SSL (the name “SSL” is colloquially still used but the actual protocol has been TLS since 1999).

A TLS connection accomplishes:

  1. Authentication — verifies you’re really talking to the server you intended (via certificates).
  2. Encryption — protects the payload from on-path observers.
  3. Integrity — prevents tampering with messages in transit.

TLS 1.2 was released in 2008 and dominated for a decade. TLS 1.3, released in 2018, is the modern default. By 2026, TLS 1.3 is what virtually all modern clients and servers negotiate.

The TLS 1.2 Handshake (For Context)

TLS 1.2 needs two round trips before any application data can flow:

1. Client → Server: ClientHello
   (supported versions, cipher suites, random nonce, extensions)

2. Server → Client: ServerHello + Certificate + ServerKeyExchange + ServerHelloDone
   (chosen version, chosen cipher, server's certificate, key-exchange params)

3. Client → Server: ClientKeyExchange + ChangeCipherSpec + Finished
   (client's key-exchange params, "now switching to encrypted mode")

4. Server → Client: ChangeCipherSpec + Finished
   (server's "now switching to encrypted mode")

5. Application data starts flowing.

Each step adds a network RTT. Setting up a TLS 1.2 connection adds ~100-200ms on top of the TCP connection establishment.

The TLS 1.3 Handshake

TLS 1.3 cuts this to one round trip:

1. Client → Server: ClientHello
   (supported versions, cipher suites, random nonce, KeyShare for ECDHE, extensions)

2. Server → Client: ServerHello + EncryptedExtensions + Certificate + Finished
   (chosen version, chosen cipher, KeyShare, server's certificate — all encrypted from this message onward)

3. Client → Server: Finished

4. Application data starts flowing.

The big change: the client sends its key-exchange parameters in the first message (the ClientHello). The server can derive the shared secret immediately and respond with everything else, including the encrypted half of the handshake, in one round trip.

For users, this means TLS 1.3 saves ~50-100ms per new connection compared to TLS 1.2.

What Each Field Means

Cipher suite

Specifies the algorithms used: key exchange, authentication, encryption, hash. TLS 1.3 simplified the cipher suite to specify only the symmetric cipher (e.g., TLS_AES_256_GCM_SHA384) — key exchange and signature algorithms are negotiated separately.

Random nonce

A random value from each side, used in key derivation. Prevents replay attacks.

KeyShare

TLS 1.3’s mechanism for ECDHE key exchange. Each side sends its public key for an elliptic curve Diffie-Hellman exchange. Both sides can then derive the same shared secret without ever transmitting it.

Certificate

The server’s identity. A chain of X.509 certificates ending at a CA that the client trusts. The client verifies:

  • The certificate is for the hostname being connected to (matches SNI / certificate Common Name / SAN).
  • The certificate chain leads to a trusted root CA.
  • The certificate hasn’t been revoked (OCSP / CRL).
  • The certificate hasn’t expired.

Finished

A MAC over the entire handshake transcript so far. Confirms that both sides saw the same handshake messages (preventing downgrade attacks).

Session Resumption: 0-RTT

TLS 1.3 supports 0-RTT session resumption. If the client has previously connected to the server, it can include encrypted data in the very first message — application data starts flowing in 0 RTT.

1. Client → Server: ClientHello + EarlyData (encrypted with previous session key)

2. Server → Client: ServerHello + Finished + EarlyDataResponse

3. Application data continues flowing.

Use cases: API calls where the request is small and idempotent, GET requests where the cost of replay is acceptable.

Caveat: 0-RTT data is replayable. An attacker who captures the encrypted EarlyData blob could replay it later. For non-idempotent operations (transactions, writes), don’t use 0-RTT.

SNI: How the Server Knows Which Cert to Serve

One server IP, many domains. How does the server know which certificate to present?

Server Name Indication (SNI) — an extension in the ClientHello that tells the server which hostname the client wants:

ClientHello {
    extensions: [
        server_name: "example.com"
    ]
}

The server uses this to pick the right certificate. Without SNI, a server hosting multiple domains couldn’t serve TLS properly.

SNI is sent in plaintext in the ClientHello (because the server needs it before encryption is set up). This means on-path observers can see which domain you’re connecting to even though the actual data is encrypted.

Encrypted Client Hello (ECH) is the 2026-current solution: it encrypts the SNI using a public key advertised in DNS. Most major sites and CDNs support ECH; it’s a meaningful privacy improvement.

Certificate Authorities and Trust

The whole TLS authentication model rests on certificate authorities (CAs). Browsers and OSes ship with a list of trusted root CAs (a few hundred). When a server presents a certificate, the client checks that the certificate chain leads to one of these roots.

If you’ve ever seen “your connection is not private” — that’s a chain validation failure. The certificate might be:

  • Expired
  • Issued for the wrong hostname
  • Self-signed (no CA in chain)
  • Issued by a CA the client doesn’t trust
  • Revoked

In 2026 the dominant free CA is Let’s Encrypt. Commercial CAs (DigiCert, Sectigo, etc.) still exist for EV certificates and specific compliance requirements, but Let’s Encrypt dominates by volume.

What “TLS” Encrypts and Doesn’t

A common confusion: TLS protects the application data. It doesn’t hide everything.

Encrypted by TLS:

  • HTTP request methods, URLs, headers, bodies
  • HTTP response status codes, headers, bodies
  • All application data within the TLS connection

Visible to on-path observers:

  • The destination IP (visible in the IP header)
  • The destination port (in the TCP header)
  • The SNI field in ClientHello (unless ECH is in use)
  • The size and timing of encrypted packets (traffic-analysis observable)
  • DNS queries (unless DoH/DoT is in use)

The full privacy stack (TLS + DoH + ECH + VPN) closes most of these gaps. Pure TLS closes the application-data gap.

TLS Performance

For an empty TLS 1.3 connection to a previously-unseen server:

  • TCP handshake: 1 RTT
  • TLS 1.3 handshake: 1 RTT
  • HTTP request: 1 RTT
  • Total: 3 RTTs before useful data

For QUIC (HTTP/3, see HTTP/2 vs HTTP/3) over UDP:

  • QUIC + TLS 1.3 handshake combined: 1 RTT
  • HTTP request: 1 RTT
  • Total: 2 RTTs

QUIC eliminates the separate TCP handshake by integrating transport and TLS into one protocol. This is one of the main reasons HTTP/3 is faster than HTTP/2 for first-request latency.

Diagnosing TLS Problems

A few practical tips when TLS misbehaves:

openssl s_client

The first-resort tool:

openssl s_client -connect example.com:443 -servername example.com

Shows the certificate chain, negotiated cipher, TLS version. Lets you read the certificate fields by hand.

curl --verbose

curl -v https://example.com 2>&1 | grep '^\*'

Shows the TLS negotiation steps inline with the HTTP request.

Wireshark

For deep diagnosis. The ClientHello and ServerHello are plaintext and visible. You can see exactly what was negotiated, what extensions were sent, etc.

Common errors

  • “unable to verify the first certificate” — Missing intermediate cert. Server must send the full chain, not just the leaf.
  • “hostname mismatch” — Cert doesn’t include the domain you’re connecting to in its SAN list.
  • “certificate has expired” — Renew via Let’s Encrypt (or your CA).
  • “handshake failure” — Usually cipher mismatch between client and server. Modern clients drop SSLv3, TLS 1.0, TLS 1.1; servers stuck on those won’t negotiate.

TLS in Your Application

For most application developers, TLS is handled by:

  • The reverse proxy / load balancer (nginx, HAProxy, AWS ALB) which terminates TLS and forwards plaintext to your backend over the internal network.
  • The CDN (Cloudflare, CloudFront) which terminates TLS at the edge.
  • The cloud platform (Vercel, Heroku, Render) which manages certs automatically.

You almost never write TLS code yourself in 2026. Where it matters:

  • Choose modern defaults. TLS 1.3 only, modern ciphers, HSTS enabled.
  • Manage certificates with automation (Let’s Encrypt + cert-manager / Caddy / ACME client).
  • Don’t pin certificates unless you have a clear threat model — pinning breaks when you renew.
  • Test with SSL Labs (ssllabs.com/ssltest) periodically.

TLS and HTTP/3

HTTP/3 doesn’t use TCP at all — it runs over QUIC, which has TLS 1.3 baked in. There’s no separate TLS handshake; the QUIC handshake is the TLS handshake. See HTTP/2 vs HTTP/3 for the broader transport changes.

TL;DR

  • TLS handshake sets up an encrypted channel before HTTP (or other application data) can flow.
  • TLS 1.2 needs 2 RTTs. TLS 1.3 needs 1 RTT.
  • TLS 1.3 + 0-RTT can resume previous sessions in 0 RTTs (for replayable requests only).
  • SNI is plaintext; ECH encrypts it.
  • TLS encrypts application data but not the destination IP/port, packet timing, or pre-ECH SNI.
  • Cert chain validation is the main reason connections fail.
  • In your applications, TLS is handled by a reverse proxy or CDN; choose modern defaults and automate certs.

The TLS handshake is a small but critical part of every secure connection. Once you’ve internalized the 1.3 flow (ClientHello → ServerHello+Finished → Finished → data), most production TLS debugging becomes straightforward. For the related encrypted-DNS layer, see DNS over HTTPS vs TLS; for the transport that wraps TLS in 2026, see HTTP/2 vs HTTP/3.

Get Started

Convert IPs into accurate location data in milliseconds.

Sign up today and get 1,000 free monthly stored conversions, and discover why developers trust us for fast, reliable, and affordable IP conversions.