Orange Book
External databases

Connect TiDB from Workers: @tidbcloud/serverless over HTTP

Workers cannot open raw TCP connections; use @tidbcloud/serverless to reach TiDB Cloud Starter/Essential over HTTP.

Edited and verified by Orange Book Editorial Team ·

INTEGRATIONSINTERMEDIATE25 minutesVerified 2026-08-27

Bottom line first

TiDB is a distributed database compatible with the MySQL protocol, but Workers cannot open raw TCP connections. The official path is @tidbcloud/serverless, which wraps queries into HTTP requests. Hyperdrive's official support list does not include TiDB; compatibility is unverified and not a recommended path.

Scope and limits

  • Only TiDB Cloud Starter / Essential clusters are supported; self-hosted TiDB or Dedicated clusters are outside this driver's scope.
  • Every query goes over HTTPS with no pooling benefit; for high-frequency short queries, measure whether the latency is acceptable.
  • Hyperdrive supports MySQL 5.7–8.x and protocol-compatible databases, but the official list does not name TiDB. Even if it works at the protocol level, do not run an unverified combination in production.

Prepare the cluster and credentials

After creating a Starter cluster in the TiDB Cloud console, take the standard MySQL connection string from the connection panel, shaped like mysql://user:pass@host/db, and store it as one secret:

npx wrangler secret put DATABASE_URL

The string contains a password, so it must go through wrangler secret — never into vars or the repository. If it leaks, reset the password in the TiDB Cloud console and update the secret.

Worker code

npm install @tidbcloud/serverless
src/index.ts
import { connect } from '@tidbcloud/serverless';

interface Env {
  DATABASE_URL: string;
}

export default {
  async fetch(request, env: Env): Promise<Response> {
    const conn = connect({ url: env.DATABASE_URL });
    try {
      const rows = await conn.execute('SELECT id, title FROM notes LIMIT 10');
      return Response.json({ notes: rows });
    } catch (error) {
      return Response.json({ error: String(error) }, { status: 502 });
    }
  },
};

Each connect call creates a stateless HTTP client — nothing to reuse across requests and no connection to close. This path needs no Wrangler binding.

Verification and troubleshooting

curl -s https://<worker>.workers.dev/notes
SymptomCheck firstRecovery
401 / authentication failureWhether the user and password in DATABASE_URL match the consoleReset the password in the console, then update with wrangler secret put
Connection timeoutsWhether the cluster is Starter/EssentialDedicated clusters need a different access method (out of scope here)
TLS-related errorsWhether the string came from the console connection panel with TLS parameters intactRecopy the full connection string without trimming parameters
High latency under frequent queriesWhether the workload actually needs poolingEvaluate Postgres plus Hyperdrive instead; see the integrations overview

Remote boundary and rollback

Creating the TiDB Cloud cluster, writing the DATABASE_URL secret, and deploying the Worker all change remote state; this tutorial does not run those actions. Rollback: remove the related routes in code and redeploy — Workers holds no connections, so there is nothing to drain. Then delete the DATABASE_URL secret in Cloudflare and reset the database password in the TiDB Cloud console. Rolling the whole approach back to D1 means exporting the data first and importing into D1 — note that TiDB speaks MySQL dialect while D1 speaks SQLite, so the schema needs a table-by-table rewrite and verification, not a plain data copy.

Next: selection recap in the external database integrations overview; monitoring after launch in Observability.

Primary sources

Did this page help you complete your goal?

Beta feedback is generated in this browser and is never uploaded automatically.

On this page