Skip to content

CockroachDB Cloud Community

Status: tested against querycop HEAD on 2026-05-20. Endpoint conventions cited as of 2026-05.

CockroachDB Cloud is the managed service for CockroachDB, a distributed SQL database that speaks the PostgreSQL wire protocol over a non-standard port (26257). Cluster tiers, as of 2026-05:

  • Basic — entry-level multi-tenant tier (the cluster formerly known as Serverless / free).
  • Standard — paid multi-tenant tier with predictable performance (the cluster formerly billed as Serverless usage- based).
  • Advanced — single-tenant cluster (formerly Dedicated).

All three tiers speak the same PostgreSQL wire protocol on port 26257 and are reached over a per-cluster FQDN. The cookbook recipe below is the same for all three tiers — tenant routing for the multi-tenant Basic / Standard tiers is now encoded in the hostname, so no --cluster=<routing-id> in the client’s options string is required (see Gotchas for the historical note and what to do if you have an old connection string still using --cluster=...).

CockroachDB Cloud does not currently expose an IAM / OAuth equivalent at the SQL wire layer — auth is SQL-user password (the control-plane has its own IAM for the dashboard / API, which is unrelated to data-plane auth). The IAM auth section is intentionally omitted from this page.

For any CockroachDB Cloud cluster (Basic / Standard / Advanced) with SQL-user-password auth, the production-ready config is:

Env varValue
GATEKEEPER_BACKEND_HOSTmy-cluster-abcd-1234.aws-us-east-1.cockroachlabs.cloud (the FQDN from the dashboard — for Basic / Standard the tenant routing is baked in here)
GATEKEEPER_BACKEND_PORT26257
GATEKEEPER_BACKEND_TLS_MODEverify-full
GATEKEEPER_BACKEND_TLS_CA_FILE/etc/ssl/certs/cockroach-cluster-ca.crt (downloaded per-cluster from the dashboard)
GATEKEEPER_BACKEND_TLS_SERVER_NAME(unset — derived from BACKEND_HOST, which matches the cert SAN)

The cookbook treats the dashboard-displayed connection string as the source of truth — paste the hostname into BACKEND_HOST and do not add options=--cluster=... either client-side or in Querycop’s env. The old --cluster=<routing-id> token is deprecated; recent CockroachDB Cloud clusters reject it or ignore it.

  • A running cluster in CockroachDB Cloud — any tier (Basic / Standard / Advanced). The cluster name, region, FQDN, and connection-string template are visible in the dashboard under Clusters → <your cluster> → Connect.

  • The cluster’s CA cert, downloadable from the same dashboard panel (Connect → Download CA Cert). CockroachDB Cloud uses a per-cluster CA, not a publicly-trusted root.

    Terminal window
    # After the dashboard download lands the file (typical local path
    # convention from Cockroach Labs is ~/.postgresql/root.crt):
    mv ~/.postgresql/root.crt /etc/ssl/certs/cockroach-cluster-ca.crt
    grep -c BEGIN /etc/ssl/certs/cockroach-cluster-ca.crt # ≥ 1
  • A SQL user created in the cluster, with a password set. Create via the dashboard’s Users section, or via SQL once you have a privileged session:

    CREATE USER appuser WITH PASSWORD '<strong-password>';
    GRANT SELECT, INSERT, UPDATE, DELETE
    ON DATABASE appdb TO appuser;
  • Network reachability from the Querycop host to port 26257 on the cluster endpoint (note: not 5432 — Cockroach uses its own port across both tiers).

  • Querycop with backend TLS support (GATEKEEPER_BACKEND_TLS_*).

CockroachDB Cloud’s data-plane auth is SQL-user password. Querycop forwards the password unchanged.

The CA cert is per-cluster — it is NOT the same across tiers or regions. Save it to a path Querycop can read:

Terminal window
# Place the dashboard-downloaded CA cert at a stable path
cp ~/Downloads/cc-ca.crt /etc/ssl/certs/cockroach-cluster-ca.crt
# Sanity check it parsed
grep -c BEGIN /etc/ssl/certs/cockroach-cluster-ca.crt # should be ≥ 1

Cockroach Labs rotates the per-cluster CA on a published schedule; the dashboard prompts ahead of rotation. When that happens, re-download and restart Querycop (no in-process hot reload of BACKEND_TLS_CA_FILE).

Terminal window
# Required: the cluster endpoint
export GATEKEEPER_BACKEND_HOST=my-cluster-abcd.aws-us-east-1.cockroachlabs.cloud
export GATEKEEPER_BACKEND_PORT=26257
# Required: full TLS verification against the per-cluster CA.
export GATEKEEPER_BACKEND_TLS_MODE=verify-full
export GATEKEEPER_BACKEND_TLS_CA_FILE=/etc/ssl/certs/cockroach-cluster-ca.crt
# SERVER_NAME not set — Querycop derives it from BACKEND_HOST,
# which matches the SAN on the per-cluster cert.
# Standard Querycop runtime — note the LISTEN_PORT is whatever your
# clients should dial; the backend port is fixed at 26257.
export GATEKEEPER_LISTEN_PORT=15432
export GATEKEEPER_API_PORT=8080
export ADMIN_API_KEY=$(openssl rand -hex 16)
querycop

The connection looks like an ordinary PostgreSQL client connection for every tier (Basic / Standard / Advanced) — Querycop translates the listen port, and the tenant routing for multi-tenant tiers is already baked into BACKEND_HOST from Step 2:

Terminal window
psql -h 127.0.0.1 -p 15432 -U appuser -d appdb
# Password prompt → enter the password set on the Cockroach user

No options=--cluster=... token is required. If your dashboard or an older runbook still shows a connection string containing options=--cluster=..., drop that token — it is deprecated and the FQDN you pasted into BACKEND_HOST already encodes the same routing.

verify-full is the right default. require (no certificate verification) is evaluation-only. disable is not an appropriate choice — CockroachDB Cloud refuses anything weaker than TLS server-side anyway, so the handshake fails immediately.

Terminal window
# Terminal 1: bring up Querycop with the env above.
docker compose up -d # or `querycop` directly
# Terminal 2: same shape for every tier (Basic / Standard / Advanced).
PGPASSWORD='<password>' psql \
-h 127.0.0.1 -p 15432 -U appuser -d appdb \
-c 'select 1'
# ?column?
# ----------
# 1
# (1 row)

A green select 1 means proxy-side handshake, backend TLS, and password auth all worked. If you see something else:

  1. backend TLS negotiation failed: x509: certificate signed by unknown authority → the per-cluster CA file is missing, stale, or wasn’t picked up. Re-download from the dashboard and update BACKEND_TLS_CA_FILE.
  2. cluster "..." not found or similar tenant-routing error → the FQDN in BACKEND_HOST doesn’t match an active cluster. Re-paste from the dashboard’s Connect panel. If the connection string the dashboard emits is in the old form with options=--cluster=..., drop that token and rely on the FQDN alone.
  3. password authentication failed for user "appuser" → wrong password or user doesn’t exist. Check via the dashboard’s Users section.

Tenant routing is now encoded in the hostname — no --cluster= options needed

Section titled “Tenant routing is now encoded in the hostname — no --cluster= options needed”

For the multi-tenant Basic / Standard tiers, the cluster’s front-door router dispatches to the right tenant by reading the hostname the client connected to. Every cluster gets its own FQDN that includes the cluster-routing identity, and the dashboard emits that hostname directly in its connection-string panel. The recipe is:

  • Paste the dashboard hostname into GATEKEEPER_BACKEND_HOST (Step 2 above).
  • Have the client connect to Querycop’s listen address. Querycop dials the backend FQDN. With GATEKEEPER_BACKEND_TLS_SERVER_NAME unset, Querycop derives the TLS SNI from BACKEND_HOST, so CockroachDB Cloud’s edge sees the dashboard-provided hostname it expects and routes accordingly.
  • Do not add options=--cluster=... anywhere — client-side connection string OR Querycop env. The token is deprecated and the FQDN is the source of truth.

If you have an older connection string still using options=--cluster=... — from a legacy dashboard view, a pre-cutover runbook, or copy-pasted from an old StackOverflow answer — recent CockroachDB Cloud clusters either ignore the token or reject it outright. Drop the token; the FQDN already carries the routing.

For the single-tenant Advanced tier, there’s no routing question at all: the FQDN points at one physical cluster, and the client connects normally. Querycop’s recipe is identical to the multi-tenant case (this is why the cookbook now has a single unified Step 3 instead of a Basic-vs-Advanced split).

If you’re running Querycop in front of a cluster where you genuinely need to inject a startup parameter the client can’t be configured with — Querycop deliberately doesn’t mutate the StartupMessage, so the right pattern is a per-client ConfigMap / env-driven connection-string template in front, not proxy-side rewriting.

This is the most common smoke-test misfire on a first deployment. CockroachDB Cloud’s backend listens on port 26257 across every tier (Basic / Standard / Advanced). If you set BACKEND_PORT=5432 by muscle memory, the dial fails immediately with connection refused.

The listen port on Querycop’s client-side (GATEKEEPER_LISTEN_PORT) can be whatever you like — 15432 is fine, your apps don’t care that the upstream is on 26257.

Cockroach Labs rotates the per-cluster CA on a published schedule; the dashboard prompts ahead of the rotation. The operator pattern:

  1. When prompted, download the new CA from the dashboard.
  2. Replace /etc/ssl/certs/cockroach-cluster-ca.crt with the new PEM.
  3. Restart Querycop (no in-process hot reload of BACKEND_TLS_CA_FILE).

The dashboard exposes both the outgoing and incoming CA during the transition window, so re-downloading well in advance avoids the cliff edge.

Client→proxy TLS vs proxy→CockroachDB TLS are SEPARATE legs

Section titled “Client→proxy TLS vs proxy→CockroachDB TLS are SEPARATE legs”
LegConfigured byDefault
Client → QuerycopGATEKEEPER_PROXY_TLS_CERT / _KEYOFF — plaintext unless you put TLS material in front
Querycop → CockroachDBGATEKEEPER_BACKEND_TLS_* (this page)prefer (default) — upgrade to verify-full per recipe

In this cookbook the proxy→DB leg is verify-full. The client→proxy leg is your call — psql over plaintext to a localhost proxy is fine for development; for production put a TLS cert on Querycop (GATEKEEPER_PROXY_TLS_CERT / _KEY).

Because CockroachDB Cloud auth is SQL-user password, that password traverses the client→proxy leg unchanged (Querycop forwards it). Don’t run app→Querycop in plaintext over a non-loopback network unless the network itself is trusted.

CockroachDB serial / unique behavior differs from stock PostgreSQL

Section titled “CockroachDB serial / unique behavior differs from stock PostgreSQL”

Not a Querycop concern, but worth knowing during onboarding: CockroachDB Cloud is wire-compatible with PostgreSQL but the underlying engine has its own semantics around:

  • SERIAL columns: CockroachDB uses unique_rowid() by default (random-looking int64) rather than a per-table sequence.
  • RETURNING clauses, ON CONFLICT, transaction retries: largely compatible but with retry-loop expectations in apps; see CockroachDB Transactions.
  • pg_catalog query shape: similar but not identical; ORM reflection can hit edge cases.

These are wire-protocol-compatible from Querycop’s perspective — the proxy doesn’t care about the result-shape differences. But if an app behaves oddly on Cockroach Cloud and you’re tempted to blame Querycop, the engine semantics are the more likely cause.

Org-level IAM is for the dashboard, NOT the SQL wire

Section titled “Org-level IAM is for the dashboard, NOT the SQL wire”

CockroachDB Cloud has its own RBAC system at the organization / project / cluster level, accessible via the dashboard and the CockroachDB Cloud API. Those identities authenticate humans / service accounts against the control plane (creating clusters, managing users, downloading CA certs, rotating credentials). They are NOT a substitute for SQL-user passwords on the data plane — the MySQL-style cockroach sql CLI and any PG-wire client must still authenticate with the SQL-user password the dashboard generated.

If you’re automating SQL-user creation from CI, you’d use a CockroachDB Cloud API token to call the users REST endpoint and then take the returned password into your secrets store — Querycop only ever sees the SQL-user password the client subsequently presents.