Learn
Anycast vs DNS Routing: How a CDN Picks the PoP
Evaluated February 2026. Two mechanisms decide which edge serves a request, and they fail on completely different ...
TLS 1.3 removes exactly one round trip from a full handshake compared with TLS 1.2, and 0-RTT removes one more on resumed connections. On a TLS 1.3 CDN edge with a 25 ms client RTT that is 25 ms off time-to-first-byte; on a 95 ms intercontinental path it is 95 ms, and up to 190 ms against TLS 1.2 when early data applies. The catch is accounting: the saving lands once per connection, not once per request, and 0-RTT only fires when the client already holds a valid pre-shared key. On public web traffic that is a minority of connections.

Count round trips to the first application byte, not milliseconds of CPU. Everything else in the handshake budget is noise by comparison.
| Path | Transport setup | Crypto setup | RTT to first byte |
|---|---|---|---|
| TCP + TLS 1.2 full | 1 | 2 | 3 |
| TCP + TLS 1.2 abbreviated (ticket) | 1 | 1 | 2 |
| TCP + TLS 1.3 full | 1 | 1 | 2 |
| TCP + TLS 1.3 PSK session resumption | 1 | 1 | 2 |
| TCP + TLS 1.3 with 0-RTT early data | 1 | 0 | 1 |
| QUIC / HTTP/3 full (RFC 9000, RFC 9001) | combined | 1 | 1 |
| QUIC / HTTP/3 with 0-RTT | combined | 0 | 0 |
Plain TLS 1.3 session resumption without early data buys you nothing in round trips over a full TLS 1.3 handshake — the entire latency win of resumption is in 0-RTT, while the win of resumption itself is in bytes and CPU.
Those bytes matter more than engineers expect. A full handshake ships the certificate chain: roughly 2–4 KB for a two-certificate ECDSA chain, 4–6 KB with RSA, plus 1–2 KB if you staple an OCSP response. With an initial congestion window of 10 segments (about 14 KB), the chain competes directly with your first HTML bytes on the same flight, and on a lossy mobile path a single dropped certificate segment costs an RTO, not an RTT.
Handshakes to the same edge hostname happen in parallel, so the saving is not additive. A navigation that opens two connections to your asset host does not save 2 × RTT from TLS 1.3; it saves one RTT on the critical path, because the second handshake overlaps the first.
Worked example, assumptions stated: 25 ms in-region RTT, one HTTP/2 connection to the page host, one to the asset host, 46 subresources. Moving from TLS 1.2 to TLS 1.3 removes 25 ms from the critical path. Enabling 0-RTT on the repeat visit removes another 25 ms. The remaining 45 requests ride the open connection and pay zero handshake cost. Total tls handshake latency saved per repeat navigation: 50 ms, or about 4% of a 1.2 s LCP. At 95 ms RTT the same change is worth 190 ms, which is 16%.
That ratio is the whole decision. 0-RTT is a long-RTT, high-connection-churn optimization. It is close to irrelevant for a single long-lived HTTP/3 connection streaming 4-second HLS segments for an hour.
TLS 1.3, standardized as RFC 8446, cuts a full handshake from two round trips to one, and 0-RTT resumption removes the last one for returning clients. Early data carries no replay protection at the protocol level: an attacker who captures a 0-RTT flight can resend it, and the server has no way to distinguish the copy from the original without additional state. RFC 8446 section 8 defines the mitigations; it does not mandate strong ones.
Two properties make this awkward specifically at the edge. First, anti-replay strike registers are node-local — a single-use ticket database is cheap within one server and expensive to make globally consistent, so a replay directed at a different edge node than the original often lands. Second, ticket keys are typically shared fleet-wide so that resumption works after a client moves between nodes, which widens the blast radius of a key compromise. Early data also lacks forward secrecy: it is protected by the resumption secret derived from the previous session, so a ticket-key leak exposes recorded early data that a full handshake would have kept safe.
The practical containment is boring and effective: accept early data only for idempotent methods with no request body, cap ticket lifetime at 10 minutes or less, validate the obfuscated ticket age against your own clock skew window, and forward the situation to the origin instead of hiding it.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_early_data on;
ssl_session_tickets on;
ssl_session_timeout 10m;
ssl_session_ticket_key ticket_keys/current.key;
ssl_session_ticket_key ticket_keys/previous.key;
proxy_set_header Early-Data $ssl_early_data;
log_format handshake '$ssl_protocol reused=$ssl_session_reused early=$ssl_early_data ttfb=$request_time';
The two ticket key files implement rotation: the first entry encrypts new tickets, later entries only decrypt, so you rotate hourly without invalidating in-flight sessions. The Early-Data header is RFC 8470 — the origin sees value 1 when the request arrived as early data and answers 425 Too Early for anything that touches state. Compliant clients then retry the same request after the handshake completes, which turns the replay question into an application-layer decision instead of a gamble at the edge.
If your terminator cannot express per-method rules, split hostnames: early data on for the static asset host, off for the API host. Whichever edge you run, that split should be a configuration change rather than an architecture change; BlazingCDN handles TLS behavior as per-property edge configuration, which is the granularity this pattern needs.
0-RTT enlarges the first client flight. A ClientHello carrying a ticket plus early data can exceed one packet, and under QUIC the server's 3x anti-amplification limit means a large early flight may still stall waiting for address validation — the 0 RTT on paper becomes 1 RTT in practice for some clients.
Anti-replay costs memory. A strike register sized for a 10-minute ticket lifetime at 50,000 handshakes per second per node holds tens of millions of entries; most implementations use a bounded Bloom filter and accept a false-positive rejection rate, which shows up as unexplained handshake retries rather than errors.
The observability gap is the real problem. Standard access logs record status and duration but not handshake type, so teams cannot answer "what share of our connections resume?" — and without that number, the 0-RTT decision is guesswork. Log the protocol version, the reuse flag, the early-data flag, and 425 counts before you tune anything.
| Workload | New-connection share | Verdict | Reason |
|---|---|---|---|
| Static assets, images, fonts | High | Enable, GET and HEAD only | Idempotent by definition; replay is harmless |
| Mobile APIs with short-lived connections | High | Enable with 425 handling | Radio churn and NAT rebinding kill keep-alive |
| HLS or DASH segment delivery | Very low | Marginal | One handshake amortized over hundreds of segments |
| Large file and game patch downloads | Low | Skip | One RTT against minutes of transfer is unmeasurable |
| Authenticated, state-changing endpoints | Any | Do not enable | Replay risk exceeds the value of one round trip |
0-RTT earns its configuration effort only where new connections are frequent and client RTT is high; everywhere else, plain TLS 1.3 session resumption already captured the win.
TLS 1.3 saves exactly one network round trip on a full handshake: two round trips of crypto negotiation become one. In wall-clock terms that is your client-to-edge RTT, typically 10–40 ms in-region and 80–150 ms intercontinental. It also removes 2–6 KB of certificate chain from the first flight on resumed sessions.
0-RTT is safe when early data is restricted to idempotent requests with no body. The protocol provides no replay protection, and edge-local anti-replay state does not stop a replay aimed at a different node. Forward the Early-Data header per RFC 8470 and let the origin return 425 Too Early for anything that mutates state.
Session resumption reuses a pre-shared key to skip certificate exchange, saving CPU and bytes but still costing one round trip. 0-RTT is an optional extension of resumption that lets the client send application data in its first flight, saving that remaining round trip. Resumption is a prerequisite for 0-RTT, not the same thing.
No. QUIC per RFC 9000 already merges transport and crypto setup into one round trip, which matches TLS 1.3 over TCP at two. QUIC 0-RTT drops that to zero for resumed connections, with the same replay caveats plus the 3x anti-amplification limit, which can stall large early flights until address validation completes.
Spend twenty minutes this week adding four fields to your edge access log: TLS version, session-reuse flag, early-data flag, and time-to-first-byte. Run it for 24 hours, then compute two numbers — the share of connections that resume, and the p95 TTFB delta between full and resumed handshakes. If resumption is under 20% of connections, your handshake budget is not the problem and 0-RTT will not fix it. If it is over 50% and your RTT p75 is above 80 ms, early data on your static hostname is one of the cheapest latency wins available. Post your two numbers to your platform channel and argue from data.
Learn
Evaluated February 2026. Two mechanisms decide which edge serves a request, and they fail on completely different ...
Security
Cloudflare Rate Limiting Pricing 2026: Plans, Rules, Real Costs Cloudflare rate limiting pricing has one detail that ...