Skip to main content

Hyperdrive MySQL on Workers: 3 Pooler Bugs and How to Test Them

Hyperdrive MySQL on Workers is GA. Three pooler bugs it hit, from lost emoji to a 0.001% empty-result cache fault, and the test that catches each.

• • 7 min read
Dashboard-style cover for Hyperdrive MySQL on Cloudflare Workers showing a Worker, client node, shared cache and endpoint node, with a 0.001 percent bug rate and 99.99 percent success target

TL;DR Hyperdrive MySQL support is now generally available, and Cloudflare’s write-up shows three pooler bugs worth testing in any MySQL stack: utf8 silently dropping emoji, COM_RESET_CONNECTION reverting the character set, and a shared cache returning bytes encoded for the wrong client. The last one hit about 0.001% of queries and returned empty results. Each has a cheap test you can run in under an hour.

Hyperdrive is Cloudflare’s database connection pooler for Workers. It holds warm SQL connections open on Cloudflare’s network, shares them across Worker requests, and can cache common queries in the CDN cache.

I read Cloudflare’s “Inside Hyperdrive: How we solved a rare Hyperdrive MySQL caching bug” (October 14, 2026) for the parts that transfer to your own setup. All facts about Hyperdrive’s internals come from that post. The tests and the checklist are my suggestions, and I did not run them against Hyperdrive.

How do you connect a Cloudflare Worker to MySQL with Hyperdrive?

Create a Hyperdrive, bind it to the Worker, and connect through the binding instead of the database host. Connecting directly costs at least five network round trips per connection, which is impractical for a Worker that starts fresh on every request. Hyperdrive absorbs that cost by keeping connections warm.

  1. Create the Hyperdrive with Wrangler:

    Bash
    npx wrangler hyperdrive create HYPERDRIVE_NAME --connection-string="mysql://user:password@db-host.example.com:3306/dbname"
  2. Add the returned ID to your Worker’s Wrangler configuration as a Hyperdrive binding.

  3. In the Worker, open the connection with the binding’s host, port, user and password instead of the origin’s.

  4. Turn on caching only after you have run the tests below, and read results from a staging origin first.

Cloudflare’s Hyperdrive documentation has the current binding syntax and driver notes, so copy that rather than my summary. You can also connect to a new PlanetScale database from the dashboard.

Why does a MySQL pooler lose emoji after a connection reset?

Because two separate MySQL defaults undo the character set you thought you negotiated. Cloudflare hit both during the beta.

The first was utf8. It is a deprecated alias for utf8mb3, which allows 1 to 3 bytes per code point, while real UTF-8 needs up to 4. Hyperdrive negotiated utf8 at handshake, so emoji written to the database were not returned correctly. The fix was to negotiate utf8mb4.

The second came from connection cleanup. A pooler shares connections across requests, so it must clear session state between checkouts. Hyperdrive added COM_RESET_CONNECTION, a lightweight command for exactly that. But the command resets the connection to the server default, not to the character set negotiated at startup. On a server that defaults to latin1, a freshly reset utf8mb4 connection becomes latin1. The fix was to always set utf8mb4 again right after a reset.

LayerWhat you setWhat silently happensFix
Handshakeutf8Treated as utf8mb3, 4-byte emoji breakNegotiate utf8mb4
After resetNegotiated utf8mb4COM_RESET_CONNECTION restores server default (latin1 here)Re-issue the charset command after every reset

Diagram of two charset failures in a MySQL pooler: a utf8 handshake becomes utf8mb3 and drops 4-byte emoji, and utf8mb4 negotiated at startup reverts to the server default latin1 after COM_RESET_CONNECTION until the charset is set again

The test: write a row containing an emoji, read it back through the pooler, then force the connection to be reused and read it again. Run it against a server whose default charset is not utf8mb4, since a server that already defaults to utf8mb4 hides the second bug.

How did a shared cache return empty MySQL results?

Client and Endpoint nodes shared one data-center cache but wrote different bytes into it. A Hyperdrive has two nodes. The Client node runs beside the Worker and does local caching. The Endpoint node holds the connection pool near the origin database. Each uses the Cloudflare CDN cache of its own data center, so when both run in the same one, they share a cache. Entries are keyed by a hash of the query’s wire messages with some normalization.

The wrinkle is that Hyperdrive talks to the origin with a fixed set of MySQL capability flags, while the Worker’s driver may support a different set. Cloudflare’s example is CLIENT_DEPRECATE_EOF, which the popular mysql2 driver does not support. With it, a result set has no EOF packet after the column definitions and ends in an OK packet. Without it, EOF packets mark both boundaries. Hyperdrive translates between the two.

The old Postgres-era assumption was that the Client could cache exactly the bytes it wrote back to the Worker. Under MySQL those bytes are in the Worker’s format, not the Endpoint’s.

Diagram of the Hyperdrive shared-cache bug: when Client and Endpoint share a data-center cache, the Endpoint stores bytes in Hyperdrive format and the Client replays them untranslated, or the Client stores Worker-format bytes and the Endpoint hands them to another Client which sends an early EOF or hangs; the fix stores one canonical Hyperdrive-format copy

ScenarioWho writes the cacheWho reads itResult
Endpoint caches, Client readsEndpoint, Hyperdrive capabilitiesClientReplies to Worker without translating
Client caches, Endpoint readsClient, Worker capabilitiesEndpoint, then a different ClientEarly EOF or a hang

The symptom was about 0.001% empty responses where a non-empty one was always expected, seen only on instances with caching enabled and only when both nodes shared a data center. That is why telemetry and traces found nothing. The fix was to always cache one canonical, Hyperdrive-capability version of the bytes, no matter which node stored it. After that, Cloudflare reports Client connection success reached 99.99%.

How do you test a MySQL pooler before trusting it?

Test the paths a happy-path demo never touches: encoding, reuse, and cached reads. A 0.001% fault will not show up in a smoke test, so the goal is to make each failure mode deterministic. This checklist is my own, derived from the three bugs.

CheckFailure it catchesHow
Emoji round triputf8/utf8mb3 handshakeInsert a 4-byte emoji, read it back
Reuse round tripCharset reverting on resetRepeat the read after forcing connection reuse, against a non-utf8mb4 server default
Cached read parityCache bytes in the wrong formatRun the same query repeatedly with caching on and compare every row count to the origin
Driver matrixCapability mismatchRun the above with each driver you ship, including mysql2
Empty-result alarmRare silent faultsAlert when a query that should always return rows returns none

The last row matters most in production. A 0.001% rate is one in 100,000 queries, so at 10 million queries a day you would see roughly 100 bad responses and no stack trace. If a query can never legitimately return nothing, treat an empty result as an error you log.

What should you take from the Hyperdrive MySQL fixes?

Never assume the bytes you send a client are the bytes you can safely cache for everyone. The cache bug was a Postgres assumption carried into a protocol with negotiable capabilities. Any proxy that translates between two protocol dialects has the same trap: cache the canonical form, translate on the way out.

If you are choosing a pooler, ask three things: what character set it negotiates, what it does after a connection reset, and whether it caches translated or canonical bytes. For related reading, see database per tenant on Cloudflare D1, which uses Hyperdrive on its control plane, Postgres migration safety and table locks and zero-downtime database migration with dual writes for the relational side, use Postgres for everything if you are still choosing a database, and deploy an MCP server on Cloudflare Workers for the platform from the application side.

Sources

FAQ

Is Hyperdrive MySQL support generally available? Yes. Cloudflare announced general availability of MySQL support for Hyperdrive in a post dated October 14, 2026. The beta ran for about a year, and Cloudflare says the gap between beta and GA was roughly twenty bug fixes.

Why did emoji break when Hyperdrive negotiated utf8? In MySQL, utf8 is a deprecated alias for utf8mb3, which stores at most 3 bytes per code point. Emoji need 4 bytes, so they only survive under utf8mb4. Hyperdrive fixed the handshake to negotiate utf8mb4.

What caused the empty MySQL results in Hyperdrive caching? The Client node cached the exact bytes it wrote to the Worker, but those bytes were translated to the Worker driver’s capabilities. When the Client and Endpoint shared a data-center cache, one node could read bytes encoded for the other, which produced empty rows or hangs about 0.001% of the time.

Does this affect me if I use mysql2 in a Worker? Cloudflare notes mysql2 does not support the CLIENT_DEPRECATE_EOF capability, which is exactly the kind of mismatch Hyperdrive translates. The cache bug is fixed on Cloudflare’s side, so the practical step is to test your own emoji, reset and cached-read paths.

How do I create a Hyperdrive for MySQL? Run npx wrangler hyperdrive create with a name and a mysql:// connection string, or create one in the dashboard. You can also point it at a new PlanetScale database, and then bind it to your Worker.

Frequently asked questions

Share this article:
X LinkedIn

Google Search · Preferred sources

Prefer this site on Google

If you already read this writing, add umesh-malik.com as a Preferred Source. Google can then highlight it with a preferred badge in Top Stories, AI Overviews, and AI Mode — for you, not as a site-wide ranking boost.

Keep reading

Get new posts on AI, Claude Code & LLMs

New deep-dives on AI engineering, Claude Code, and developer tooling — follow along however you prefer.