PlanetScale — Faster MySQL with HTTP/3¶
Summary¶
Matt Robenolt (PlanetScale) reports on an experimental proof-of-concept
database/sql-compatible Go driver that speaks HTTP/2 or HTTP/3 to
PlanetScale's public gRPC-compatible HTTP API instead of using the
native MySQL binary protocol. The driver encodes queries with
protobuf over connect-go (gRPC-compatible)
with Snappy compression; HTTP/2 uses the stdlib Go HTTP
client, HTTP/3 uses the experimental quic-go library.
Seven benchmark shapes × three clients (MySQL binary / psdb HTTP/2 /
psdb HTTP/3) × two network shapes (high-latency laptop in Reno NV;
low-latency EC2 us-west-2) — reveal that HTTP beats the MySQL
binary protocol on cold-start Connect + SELECT 1 in both
scenarios (162 ms → ~35 ms high-latency; 11 ms → 3–4 ms low-latency),
that HTTP/3 only meaningfully pulls ahead of HTTP/2 on large
payloads over unreliable high-latency networks (QUIC smooths over
TCP packet loss), and that quic-go's current immaturity makes
HTTP/3 slower than HTTP/2 on low-latency networks at large payload
sizes. Post motivates the architectural direction: serverless
runtimes can't open raw TCP sockets to speak MySQL's wire protocol
anyway, so an HTTP API is required — and HTTP's connection
multiplexing + TLS 1.3 0-RTT + (HTTP/3's) QUIC transport can
actually be faster than the binary protocol for many workloads.
Key takeaways¶
-
The architectural motivation is serverless-constrained, not performance-first. Robenolt frames the HTTP API as a requirement for serverless compute contexts that "are fundamentally not able to open up a TCP socket and speak the MySQL binary protocol" — the platforms force HTTP(S). The HTTP API already exists to support the PlanetScale Serverless driver for JavaScript and PlanetScale Connect. The benchmark post is the retrospective "does it cost us performance to serve this constraint?" answer — and the answer is generally no, often the opposite. (Source: sources/2026-04-21-planetscale-faster-mysql-with-http3)
-
HTTP wins decisively on cold-start cost in both network shapes.
Connect + SELECT 1(new connection, serial): - High-latency laptop (Reno NV →
us-west-2): MySQL min 162 ms vs HTTP min ~35 ms — a ~4.6× reduction, with MySQL's max jumping up while HTTP's stays steady. -
Low-latency EC2
us-west-2: MySQL 11 ms vs HTTP 3–4 ms — even on the fastest possible client-server proximity, HTTP shaves ~2/3 of the cold-start cost. Robenolt attributes this primarily to TLS 1.3 adoption: HTTP/2 and HTTP/3 use TLS 1.3 (HTTP/3 requires it); TLS 1.3 supports 0-RTT handshake resumption, saving a full round trip. "While, in theory, MySQL clients could also support TLS 1.3, TLS support in clients is typically not great and, in this case, negotiated with TLS 1.2." -
Parallel-connection
SELECT 1(warmed pool) is a draw. The three protocols are statistically indistinguishable once you pay the connection cost up-front. "What this does prove is that we aren't adding anything measurably worse to the connection in the fastest scenarios. We'd expect the weight of the protocol itself to overpower the actual data being transferred." Canonical result: the HTTP overhead is amortised-away at steady state. -
Medium payloads (~50 KB SELECT; bulk INSERT of the same) show tail-latency improvements over high-latency links and parity over low-latency links. The INSERT case is where HTTP structurally wins: "this is an opportunity for our HTTP API to use client-side compression, which we cannot do with the MySQL protocol." First-party canonicalisation of client-side query compression as a structural advantage HTTP gives database access that the MySQL wire protocol cannot match.
-
Large payloads (10k rows × 11 cols = ~27.5 MB SELECT; 2000-row bulk INSERT) are where HTTP/3 starts to beat HTTP/2. On high-latency networks, QUIC smooths over TCP packet loss that HTTP/2 suffers from head-of-line blocking through. "I suspect this is because, with this size of a payload, we're potentially able to exhibit packet loss and other warts of TCP, which QUIC smooths over." First wiki canonicalisation of the HTTP/3 > HTTP/2 on large payloads over unreliable networks framing from the database-transport voice.
-
Counter-intuitive finding: on low-latency networks with large payloads, HTTP/3 is measurably slower than HTTP/2. Robenolt hypothesises this is
quic-goimmaturity, not a QUIC-protocol defect: "I haven't dug into this, but my hypothesis is that this is a performance limitation in the underlyingquic-goimplementation due to it being a bit more immature and less battle-tested. At these larger payloads, we might be beginning to stress the underlying QUIC implementation as well as the underlying mysqld and hardware." Canonical wiki datum: HTTP/3's benefit floor depends on library maturity; mature TCP-based libraries still beat immature QUIC libraries on reliable networks. -
Connection multiplexing is a structural amplifier of the cold-start win. "The HTTP API multiplexes many traditional MySQL connections over a single HTTP connection, reducing the need to open many connections and maintain a connection pool." Canonical new patterns/multiplex-many-database-connections-over-one-http-connection pattern — for serverless + ephemeral runtimes (PHP per- request, periodic jobs, AWS Lambda-style FaaS), the cost of a MySQL connection per invocation is structurally prohibitive; multiplexing N logical database sessions over one shared HTTP/2 or HTTP/3 connection converts per- invocation connection cost into shared-pool cost.
-
Production deployment: PlanetScale's in-product web console ("the in-product PlanetScale web console") already uses HTTP/3 transparently when accessed from a modern browser. "If you use the in-product PlanetScale web console and a modern browser, you will connect over HTTP/3 and not even be aware of it." Production availability is transparent-to-user: no protocol-negotiation dialog, no configuration toggle — HTTP/3 is used if the browser supports it. Robenolt notes: "Unfortunately, HTTP/3 lacks a lot of adoption outside of web browsers due to being radically different."
Systems / concepts / patterns extracted¶
- Systems: PlanetScale HTTP API (the gRPC-compatible public HTTP surface), [[systems/ planetscale-serverless-driver-js|PlanetScale Serverless driver for JavaScript]] (existing production consumer of the HTTP API), connect-go (gRPC- compatible RPC framework PlanetScale uses on the server- side), quic-go (experimental Go QUIC library used client-side in the benchmark PoC), Snappy compression (the client-side wire-encoding compressor), MySQL (baseline comparison), gRPC (the RPC protocol the HTTP API is compatible with).
- Concepts: HTTP/3 (already on wiki; extended with database-transport framing), [[concepts/cold- start-connection-cost|cold-start connection cost]] (new; the primary target metric of HTTP-over-binary-protocol wins), TLS 1.3 0-RTT handshake (new; the mechanism behind the cold-start win), QUIC transport (new; UDP-based reliable transport underlying HTTP/3), [[concepts/connection -multiplexing-over-http|connection multiplexing over HTTP]] (new; the N-MySQL-sessions-on-one-HTTP-connection primitive), client-side query compression (new; structural advantage of HTTP over binary protocols), serverless TCP socket restriction (new; architectural forcing function for the HTTP API).
- Patterns: HTTP API alongside binary protocol (new; canonical shape for databases that want to serve both traditional TCP clients and serverless+browser consumers), [[patterns/http3-over- http2-for-unreliable-networks|HTTP/3 over HTTP/2 for unreliable networks]] (new; when to prefer HTTP/3 based on network-reliability signal and payload-size signal), [[patterns/multiplex-many-database-connections-over-one-http -connection|multiplex many database connections over one HTTP connection]] (new; connection-pool replacement for serverless / FaaS / ephemeral runtimes).
Benchmark shapes (verbatim)¶
Three clients tested across two network environments:
- Clients: MySQL binary protocol client;
psdb(PlanetScale HTTP API) over HTTP/2;psdb + h3(PlanetScale HTTP API) over HTTP/3. - Network A (high-latency, low-bandwidth, far): personal
laptop in Reno, NV → PlanetScale database provisioned in AWS
us-west-2. - Network B (low-latency, high-bandwidth, close): EC2
instance in AWS
us-west-2→ same database.
Seven tests per client × network:
- Connect +
SELECT 1: cold-start test — open a new connection, runSELECT 1, close, repeat serially. Targets handshake cost (TCP setup + TLS negotiation + MySQL login or HTTP handshake). - Parallel
SELECT 1: warmup a connection pool, then runSELECT 1in parallel. Targets protocol overhead on the hot path after connection cost is amortised away. - Medium
SELECT:SELECT * FROM medium(250 rows × 2 columns ≈ 50 KB result set). - Medium
INSERT: bulkINSERT INTO medium (...) VALUES (...)of the same 250 rows × 2 columns. - Large
SELECT: 10,000 rows × 11 columns ≈ 27.5 MB result set. - Large
INSERT: bulk insert of 2,000 rows per execution.
Raw data + all charts are linked from the original post.
Operational numbers¶
- Cold-start
Connect + SELECT 1, high-latency (laptop → us-west-2): MySQL min ~162 ms; HTTP min ~35 ms. MySQL max jumps up (tail latency worse); HTTP max stays steady. - Cold-start
Connect + SELECT 1, low-latency (EC2 → us-west-2): MySQL ~11 ms; HTTP ~3–4 ms. - Parallel
SELECT 1: all three protocols within the noise floor of each other. - Medium
SELECT: HTTP variants show tail-latency improvements on high-latency; low-latency bottlenecks on mysqld itself. - Medium
INSERT: HTTP shows dramatic win on high-latency due to client-side compression; not possible with the MySQL protocol. - Large
SELECT+INSERT, high-latency: HTTP/2 brings minor improvements, HTTP/3 pulls a big lead — QUIC smooths over TCP packet loss on the unreliable path. - Large
SELECT+INSERT, low-latency: HTTP/3 measurably slower than HTTP/2 — hypothesisedquic-goimplementation immaturity rather than protocol defect.
Caveats + what the post doesn't quantify¶
- Experimental PoC, not production code. "Most of what I will be discussing is not publicly documented and is entirely experimental." The benchmark driver is not a shipping artefact; no numbers on the already-production JS Serverless Driver's real-world performance.
- Benchmark on "not-fully-capable backend." "I also suspect these are a bit skewed here with bottlenecking on mysqld and the underlying disks. This might be worth revisiting again with a more capable backend so we're not as limited." Large-payload benchmarks saturate mysqld and disk I/O, not the protocol — protocol differences are compressed against the bottleneck.
- Only Go measured. Client-side results are tied to the
Go standard-library HTTP/2 implementation and the
experimental
quic-golibrary; Node.js / Rust / C++ implementations are structurally different. - No tail-percentile disclosure beyond min/max. No p95 / p99 / p99.9 reporting; no coefficient-of-variation numbers on the hot-path tests; "min vs max" is a rough stand-in.
- Single network-shape sample per environment. Reno →
us-west-2andus-west-2→us-west-2are two points on a latency curve; no results for inter-region AWS, for transcontinental (US → EU / US → APAC), or for degraded links (packet loss explicitly tested — not; inferred). - No quantified packet-loss testing. Robenolt states HTTP/3 solves "a few issues with TCP when it comes to unreliable networks, which I didn't explicitly test for." The "HTTP/3 wins on unreliable networks" claim is extrapolation from QUIC's design + observed large-payload win, not a loss-rate-parameterised measurement.
- HTTP/3 adoption caveat: "HTTP/3 lacks a lot of adoption outside of web browsers due to being radically different." Most non-browser HTTP/3 deployments remain experimental, including this one.
- Connection-migration semantics: QUIC supports graceful connection migration across network changes (IP changes, NAT rebinding); not tested or quantified in this post.
- Non-latency benefits elided: "there are other benefits that aren't discussed here that come with an HTTP API that I will be talking about when we start to publicly document these in the coming months."
- No schema / cost-per-byte comparison. MySQL binary wire format is compact (row-column binary encoding); protobuf encoding through connect-go with Snappy compression is different bytes on the wire — trade-off not quantified outside of end-to-end timing.
- Experimental
quic-gotuning state: no Go version, noquic-goversion, no buffer-size tuning, no Linux kernel UDP-socket-buffer discussion — HTTP/3 performance on low-latency large payloads may be improvable with tuning.
Source¶
- Original: https://planetscale.com/blog/faster-mysql-with-http3
- Raw markdown:
raw/planetscale/2026-04-21-faster-mysql-with-http3-66b1145e.md
Related¶
- PlanetScale — vendor context
- PlanetScale HTTP API — the system the driver talks to
- PlanetScale Serverless driver for JavaScript — first production consumer
- MySQL — binary-protocol baseline
- gRPC — RPC protocol the HTTP API is compatible with
- connect-go — server-side RPC framework
- quic-go — Go QUIC client library
- Snappy — compressor
- HTTP/3
- cold-start connection cost
- TLS 1.3 0-RTT handshake
- QUIC transport
- connection multiplexing over HTTP
- client-side query compression
- serverless TCP socket restriction
- HTTP API alongside binary protocol
- HTTP/3 over HTTP/2 for unreliable networks
- multiplex many database connections over one HTTP connection
- PlanetScale (company)