Skip to content

PLANETSCALE 2023-01-04 Tier 3

Read original ↗

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

  1. 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)

  2. HTTP wins decisively on cold-start cost in both network shapes. Connect + SELECT 1 (new connection, serial):

  3. 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.
  4. 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."

  5. 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.

  6. 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.

  7. 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.

  8. Counter-intuitive finding: on low-latency networks with large payloads, HTTP/3 is measurably slower than HTTP/2. Robenolt hypothesises this is quic-go immaturity, not a QUIC-protocol defect: "I haven't dug into this, but my hypothesis is that this is a performance limitation in the underlying quic-go implementation 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.

  9. 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.

  10. 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, run SELECT 1, close, repeat serially. Targets handshake cost (TCP setup + TLS negotiation + MySQL login or HTTP handshake).
  • Parallel SELECT 1: warmup a connection pool, then run SELECT 1 in 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: bulk INSERT 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 — hypothesised quic-go implementation 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-go library; 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-2 and us-west-2us-west-2 are 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-go tuning state: no Go version, no quic-go version, 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

Last updated · 347 distilled / 1,201 read