Skip to content

CONCEPT Cited by 2 sources

SSL handshake as per-request tax

Definition

SSL handshake as per-request tax is the condition where a request-processing model opens a fresh TLS connection per request — rather than reusing a persistent connection — causing the TLS handshake cost (2-3 RTT + asymmetric-crypto operations) to be billed against every request's latency budget. When the query or RPC being executed over the TLS connection is small and fast (e.g., a 0.3 ms database query), the handshake cost dominates the actual useful work by an order of magnitude or more.

Canonical quantitative demonstration

Against PlanetScale MySQL from PHP Laravel on AWS Lambda via Bref in classic shares-nothing mode:

  • Query execution (server-side): 0.3 ms median
  • HTTP request p50 (client-side, Lambda duration): 75 ms
  • HTTP request p95: 130 ms

After switching to Laravel Octane which persists the DB connection across requests (OCTANE_PERSIST_DATABASE_SESSIONS=1):

  • HTTP request p50: 14 ms (5.4× reduction)
  • HTTP request p95: 35 ms (3.7× reduction)

The 61 ms p50 savings decomposes approximately as TLS handshake + MySQL auth handshake + Laravel bootstrap. The TLS handshake specifically is the single-largest atomic chunk because it's RTT- bounded (waiting on network roundtrips) and crypto-bounded (ECDHE key exchange, certificate verification). (Source: sources/2026-04-21-planetscale-serverless-laravel-applications-with-aws-lambda-and-planetscale: "Since Laravel connects to PlanetScale over SSL, creating the SSL connection can take longer than running the SQL query itself.")

Why the tax exists

A TLS handshake (TLS 1.2) requires 2 network RTTs before the first application byte:

  1. ClientHello → ServerHello (1 RTT): negotiate TLS version, cipher suite.
  2. Certificate + Key Exchange → Finished (1 RTT): server sends cert chain, client verifies, ECDHE key exchange, both sides confirm.

Total: 2 RTT + certificate verification + ECDHE computation. At a typical Lambda-to-PlanetScale path latency of ~5-10 ms per RTT plus crypto overhead, that's ~15-30 ms of handshake before the first SELECT query byte transfers.

TLS 1.3 reduces this to 1 RTT for fresh handshakes and 0 RTT for resumed sessions (see TLS 1.3 0-RTT) — but only when a prior session exists to resume. Shares-nothing PHP never has a prior session; every invocation is the first.

When it's a tax, when it's not

It's a tax when: - The request model opens a fresh connection per request (shares-nothing PHP, some serverless runtimes, simple HTTP clients without connection pooling). - The underlying work (query, RPC) is cheap enough that handshake dwarfs it. Typical threshold: any RPC under ~10 ms has the handshake as the dominant cost. - TLS 1.3 session resumption is unavailable because there's no prior session to resume from.

It's not a tax when: - A persistent process holds one connection and multiplexes many requests over it (Node.js, Python ASGI, Go, Java — any persistent-process runtime). - The work is expensive enough that handshake is noise (a 1-second analytical query doesn't care about a 20 ms handshake). - TLS 1.3 session resumption is warm (second-and-later requests to the same endpoint from the same client).

Fix patterns

Persistent process (client-side)

Keep one connection alive across many requests within a persistent process. Canonical instances:

Canonical demonstration: Octane + Bref drops p50 from 75 ms to 14 ms against PlanetScale by keeping the connection warm across BREF_LOOP_MAX = 250 Lambda invocations.

Proxy-tier pooling (server-side)

A database proxy that terminates client TLS once, holds persistent connections to origin, and multiplexes client requests over them. See patterns/two-tier-connection-pooling and PlanetScale Global Routing Infrastructure. The proxy pays the handshake tax once per long- lived proxy-to-origin connection, amortised across many short- lived client connections. The client still pays a client-to-proxy handshake, but if the proxy is geographically close (edge POP) that handshake is faster than client-to-origin.

HTTP-multiplexed driver (protocol change)

Change the wire protocol to HTTP/2 or HTTP/3 with connection reuse. One long-lived HTTP/2 connection multiplexes many logical queries, paying one TLS handshake for thousands of queries. See patterns/multiplex-many-database-connections-over-one-http-connection and the PlanetScale serverless driver.

Connection pooler (middleware)

Stand a connection pooler like PgBouncer between clients and the database to hold long-lived origin connections and multiplex short-lived client connections over them. Same shape as proxy-tier pooling but as a standalone middleware component.

Seen in

Last updated · 470 distilled / 1,213 read