Overview
TiDB is a distributed, MySQL-compatible database designed for horizontal scalability and high availability. It separates compute from storage across three components: a SQL processing layer (tidb-server), a distributed key-value store (TiKV), and a placement driver (PD) that holds cluster metadata and decides where data lives. This template deploys all three tiers across one or more Control Plane locations using PingCAP’s official images, with an optional ProxySQL connection pooler in every location and optional scheduled backups to AWS S3 or Google Cloud Storage. Database credentials are not template values: the root password, application user, password and database name come from a dictionary secret you create before installing, so none of them pass through Helm or land in the release. Root gets its password while the cluster bootstraps, before any TiDB server accepts a connection.cpln workload exec, cpln logs and uninstalling all work against that GVC, and uninstalling can never delete it. Every location you list in locations must already be on that GVC. A GVC location you did not list simply starts nothing — the console shows it as This workload location is deactivated because maxScale is set to 0., which is the expected state, not a fault.What Gets Created
Prerequisites
Two things must be in place before you install: a GVC that has every location you intend to use, and a credentials secret. Backups additionally need a bucket and a cloud account — see Backing Up.Make sure the GVC has every location you will list
locations must be on it. Read the GVC’s locations from spec.staticPlacement.locationLinks:aws-us-east-1. If your GVC uses a different location, set locations at install time (see Installation). This release starts nothing in a GVC location you did not list, but other workloads in that GVC do run in every location the GVC has, so add locations to a shared GVC deliberately.Create the database credentials secret
autoCreateDatabase.enabled is true (the default). A dictionary secret holding exactly four keys — rootPassword, user, password and db. The cluster sets the root password and creates that user and that database while it bootstraps. Secrets are org-level, so no --gvc flag is involved:user must be 1–32 characters, and db 1–64 characters and not ending in a space; the TiDB servers refuse to start otherwise and name the key in their logs. Any characters are allowed in the passwords.Set autoCreateDatabase.credentialsSecretName to this name. Secret names are org-wide, so give each release its own.Installation
Create the credentials secret first, then install into the GVC that has your locations:locations is a list, so when your GVC does not use the default aws-us-east-1 pass it in a values file rather than with --set (a --set locations[0].name=... on its own replaces the whole list element and drops tikvReplicas and serverReplicas):
UI
CLI
Terraform
Pulumi
Configuration
Locations
tikvReplicas and serverReplicas set the TiKV storage nodes and TiDB SQL servers in that location independently. pdReplicas members are spread evenly across locations, with any remainder going to the first ones. A count of 0 is refused at render — remove the location from the list instead.
Clients reach only the TiDB servers in their own location, so run your applications in a location listed in locations. A client in a GVC location this release does not run in cannot connect. Set serverReplicas to 2 or more to keep a location serving when one of its SQL servers fails.
The default — one location, three TiKV nodes, three SQL servers, three PD members — survives the loss of a node. It does not survive the loss of a location. For that, use three locations with one PD member and one TiKV node each:
Images and Resources
images.* together with backup.image: from v8.5.7, br enforces a version match with the cluster. The shipped sizes are for testing. For production, PD wants 4–8 CPU / 8–16Gi, tidb-server 8–16 CPU / 16–32Gi (it scales with concurrent connections), and TiKV 8–16 CPU / 32–64Gi.
Database Initialization
credentialsSecretName names the prerequisite secret from Prerequisites. With enabled: true, the first TiDB server sets the root password and creates the application user and database while the cluster bootstraps, before it accepts any connection. Every TiDB server then becomes ready only once root refuses an empty password, so root is never reachable without one.
With enabled: false, root starts with no password and no user or database is created. Set a root password with ALTER USER before any client can reach the cluster.
RELEASE_NAME-tidb-db-init is a backstop: a cron job in the first entry of locations that sets the root password and creates the user and database if they are missing. On a fresh install it finds the work already done and exits, so every run is a no-op and schedule only controls how often it checks. Once the cluster is initialized, upgrade with deployInitWorkload: false to remove the job and its script secret; tidb-server keeps its reference to the credentials secret.
Connection Pooling (ProxySQL)
proxysql.enabled: true the template runs a ProxySQL connection pooler in every configured location, in front of that location’s TiDB servers. Clients then connect to RELEASE_NAME-proxysql.GVC_NAME.cpln.local:4000 instead of RELEASE_NAME-server, with the same users and passwords (see Connecting).
- Requires
autoCreateDatabase.enabled: true. ProxySQL authenticates clients with theuser,passwordandrootPasswordfrom the credentials secret; the chart refuses to render withproxysql.enabledon andautoCreateDatabase.enabledoff. - Reachable by whoever
internal_access.serverallows — the pooler follows the SQL tier’s access setting. - Clients must connect with a utf8mb4 charset. Every modern driver defaults to it; the
mysqlcommand-line client takes its charset from the OS locale, so pass--default-character-set=utf8mb4.
Storage
snapshots.schedule and each snapshot is kept for retentionDuration; both volume sets also take a final snapshot when deleted. A schedule more frequent than hourly is refused at render, and "" turns snapshots off.
Volume snapshots are per volume and crash-consistent: they protect against losing a single volume. To restore a whole cluster, use a br backup (see Backing Up).
Access
workload-list, list only your clients. Every workload this release creates is always allowed, whatever you set — the three tiers have to reach each other, and each tier’s own replicas have to reach each other.external_access.*_outboundAllowCIDR opens outbound internet access per tier. When backup.enabled is true, TiKV gets 0.0.0.0/0 outbound regardless, because TiKV uploads backup data to the bucket directly. There is no public inbound access to the MySQL port: reach tidb-server over internal GVC DNS or with cpln port-forward (see Connecting). Allow several minutes for an access change to take effect before concluding it did not apply.
Backup
backup.location must be one of locations; the chart refuses to render otherwise, because the backup cron runs only there. Bucket, cloud account and access setup for both providers are under Backing Up.
Connecting
.GVC_NAME.cpln.local form; the bare workload name is not reliable. Run the client in a location listed in locations — clients reach only the servers in their own location. From a workload in the same GVC, connect with any MySQL client:
RELEASE_NAME-proxysql.GVC_NAME.cpln.local instead. Without it, clients connect to RELEASE_NAME-server directly.
The pingcap/tidb image ships no MySQL client, so to verify from your own machine forward the port and use a local client:
--location LOCATION_NAME to pick which location’s replica runs the command. A fresh install takes about 5 minutes to accept connections in one location, and 10 to 15 minutes when its locations span regions or clouds.
Operations
Backing Up
Whenbackup.enabled is true, the RELEASE_NAME-tidb-backup cron workload runs TiDB’s br backup full on backup.schedule from backup.location and writes a full cluster snapshot to BUCKET/PREFIX/tidb-TIMESTAMP/. TiKV nodes upload their data to the bucket directly, which is why the template opens TiKV outbound access whenever backups are on. Keep backup.image on the same TiDB version as images.*.
- AWS S3
- Google Cloud Storage
Create the bucket
backup.aws.bucket to its name and backup.aws.region to its region.Create a cloud account
backup.aws.cloudAccountName to its name.Create the IAM policy
YOUR_BUCKET_NAME, and set backup.aws.policyName to its name:Enable backups
backup.enabled: true, backup.provider: aws, backup.location to one of your locations, and backup.aws.prefix to the folder path for backups, then upgrade the release:Backup completed:
backup.location:
Restoring a Backup
br restore full restores a backup into a new, empty release. It must run inside the GVC with a br that matches the cluster version, and the target release’s TiKV nodes read the backup files from the bucket with the target release’s own identity. The target’s backup cron workload meets all three conditions, so the restore runs there. Rehearse a restore into a scratch release before you need one.
Install an empty target release
autoCreateDatabase.enabled: false so the cluster holds no data before the restore, and with its backup section pointing at the same provider, bucket and cloud account as the backup you are restoring. Until the restore finishes, the target’s root has no password.Run br restore full from the target's backup workload
locations: replica-0.RELEASE_NAME-pd.LOCATION_1.GVC_NAME.cpln.local:2379, replica-0.RELEASE_NAME-pd.LOCATION_2.GVC_NAME.cpln.local:2379, and so on — br needs one that answers and finds the rest. Run it in the target’s backup.location. For S3:gcs:// storage URL and add --send-credentials-to-tikv=false — without it the restore fails with You should provide '--gcs.credentials-file':Confirm the restore
Successful in the cron’s history, and its output contains Full Restore success summary:Upgrading from 1.x
Template versions through 1.8.1 created their own GVC, so that GVC is part of the 1.x release’s manifest. Versions 2.0.0 and later do not declare it — and Helm deletes what a chart stops declaring.Recover the credentials the existing cluster uses
RELEASE_NAME-tidb-user; from 1.8.0 they live in the secret you created. Read them back with cpln secret reveal SECRET_NAME -o yaml. Any password that came from a pre-1.8.0 default was published in the public template repository — treat it as compromised and choose a new one for the new cluster.Back up the old cluster
backup on the 1.x release, or run br backup full by hand against its PD endpoint.Choose the GVC for the new release
locations. See Prerequisites.Install 2.2.0 as a new empty restore target
autoCreateDatabase.enabled: false, and a backup section pointing at the provider, bucket and cloud account the 1.x backup went to.Restore and cut over
RELEASE_NAME-server.GVC_NAME.cpln.local:4000 endpoint. The restored cluster keeps the 1.x cluster’s users and passwords; change any compromised password with ALTER USER as in Rotating Credentials.Uninstall the old release against the GVC you installed it into
gvc.locationsis now the top-levellocations,gvc.pdReplicasis now the top-levelpdReplicas, andgvc.nameis gone.devModeis gone.locationsmay hold a single location, and PD’s replication factor is derived from the number of TiKV nodes you configure.exposeServeris gone. It never published the MySQL port — the only thing the public endpoint would have served was tidb-server’s unauthenticated status API. Reach the server over internal GVC DNS orcpln port-forward.autoCreateDatabase.database.*is gone (since 1.8.0): the four values are the prerequisite dictionary secret named byautoCreateDatabase.credentialsSecretName.replicason a location is nowtikvReplicasplusserverReplicas(split in 2.1.0). A count of0is refused; remove the location fromlocationsinstead.
exposeServer: false and devMode: false fail too, each with an error naming the key and its replacement.
Upgrading from 2.0.0
2.0.0 and 2.2.0 both deploy into an existing GVC, so this is a plaincpln helm upgrade with one values change. Everything in Upgrading from 2.1.0 applies to this upgrade too.
Check the 2.0.0 cluster is healthy
--location LOCATION_NAME):"Up". If one is not "Up" and the cluster has never served queries, it holds no data: uninstall it and install 2.2.0 fresh. If it has been serving with a store down, back it up and restore into a fresh 2.2.0 release (see Backing Up and Restoring a Backup).Split replicas into tikvReplicas and serverReplicas
locations entry, replace replicas: N with tikvReplicas: N and serverReplicas: N to keep your current shape exactly:replicas, so an upgrade with your old values file fails before touching anything:Upgrade the release
proxysql.enabled: true.
Upgrading from 2.1.0
An in-placecpln helm upgrade with your existing values file; nothing about how clients connect changes.
Check that root refuses an empty password
cpln port-forward as in Connecting, log in as root with no password:ERROR 1045. If it connects, root has no password: keep autoCreateDatabase.deployInitWorkload: true for the upgrade. Each new TiDB server then waits about 2 minutes before serving and logs a WARNING that root accepts an empty password, and the init job sets the password from your credentials secret.Plan for one restart of every workload
Upgrade the release
- Volume snapshots start. Every PD and TiKV volume is snapshotted daily at 03:00 UTC and kept for 7 days. Set
volumeset.tikv.snapshots.scheduleandvolumeset.pd.snapshots.scheduleto""to keep them off. See Storage. - The init job runs only in the first entry of
locations. - ProxySQL no longer uses a startup-script secret, so the upgrade deletes
RELEASE_NAME-tidb-proxysql-startup. ProxySQL now also loads credentials that contain a'. - An existing cluster keeps its root password. Root’s password is set at bootstrap only on clusters created by 2.2.0 or later.
Scaling and Availability
What each failure needs. Your application never has to pick another server for anything inside a location: the template and TiDB handle that, and the application needs only the ordinary retry described below. The one thing they cannot handle is the loss of a whole location, because a client reaches only the database in its own location.- Retry failed connections with a short backoff (about 0.5–1 seconds) for 10–15 seconds. Without ProxySQL, this is what covers a TiDB server crash: for several seconds new connections can still reach the server that died. ProxySQL retries those for you, but a ProxySQL replica that dies still drops the connections going through it.
- Retry a failed statement, and make retried writes idempotent: a statement running on a process that fails returns an error, and may already have committed.
- Set a client timeout of 60 seconds, so a write pause during a leader election, a PD or TiKV restart or an upgrade is a delay rather than an error.
- Node loss. The default shape (one location, three TiKV nodes, three PD members) keeps serving through the loss of a node. A TiDB server stays in service while TiKV is partly unavailable; affected statements return errors until TiKV recovers, without restarting the SQL tier.
- Location loss. Needs at least three locations with PD spread one per location, as in the Locations example. Clients in the lost location cannot connect until it returns; clients elsewhere keep working, so run your application in at least 2 listed locations.
-
SQL server loss. Clients reach only the servers in their own location, so
serverReplicas: 2or more is what keeps a location serving through a server failure. Adding ProxySQL in front smooths that over further. -
Adding TiKV and tidb-server capacity. Raise
locations[].tikvReplicasorlocations[].serverReplicasand upgrade. New TiKV stores register with PD and receive data; new tidb-server replicas join behind the same internal address. - PD’s replication factor is fixed at bootstrap. It is the number of TiKV nodes you configure, capped at 3, and PD persists it — scaling TiKV up later does not raise it. Start with at least 3 TiKV nodes if you ever want 3-way replication.
-
Scaling in (reducing
tikvReplicas) and changingpdReplicason a running cluster are not covered by this template and have not been exercised. TiKV stores hold data; consult the TiDB documentation on scaling in before removing any. -
Storage. Enable
volumeset.tikv.autoscalingto grow TiKV volumes as they fill. PD volumes are fixed-size.
Rotating Credentials
The credentials secret is applied on first initialization only. Changing it afterwards does not change the cluster — it only changes what the init job and your clients present. Rotate inside TiDB first, then update the secret:cpln://secret reference is resolved when a replica starts and is never re-read while it runs, so force a redeployment of tidb-server afterwards so its environment matches:
autoCreateDatabase.deployInitWorkload: false before rotating — it checks the database with the credentials in the secret on every run.
Troubleshooting
The deployment never starts and the logs are empty
The deployment never starts and the logs are empty
cpln logs returns nothing for RELEASE_NAME-server or RELEASE_NAME-tidb-db-init, and the workload never becomes ready.Cause: the credentials secret named by autoCreateDatabase.credentialsSecretName does not exist. The container never runs, so there is nothing to log.Fix: read the message, create the secret, and force a redeployment:PD restarts with FATAL locations declared in values are not in GVC
PD restarts with FATAL locations declared in values are not in GVC
RELEASE_NAME-pd crash-loops and its logs contain:locations names a location the GVC does not have. The platform accepts the install; PD refuses to bootstrap a cluster whose members can never all appear.Fix: add the location to the GVC, or remove it from locations and upgrade. Check the GVC with cpln gvc get GVC_NAME -o yaml (spec.staticPlacement.locationLinks).A GVC location shows red with This workload location is deactivated because maxScale is set to 0
A GVC location shows red with This workload location is deactivated because maxScale is set to 0
This workload location is deactivated because maxScale is set to 0.Cause: the GVC has a location you did not list in locations. Nothing TiDB-related runs there by design. The init and backup cron jobs show This workload location is deactivated because suspend is set to true in every location except the one they run in, for the same reason.Fix: none needed. To use that location, add it to locations with tikvReplicas and serverReplicas counts and upgrade.tidb-server never becomes ready
tidb-server never becomes ready
RELEASE_NAME-server stays unready after install.Cause: a TiDB server reports ready only once it has started against the cluster, and that needs a healthy PD and registered TiKV stores. Either tier is still starting, or TiKV cannot reach PD.Fix: check the other tiers in order — PD first, then TiKV:tidb-server restarts with FATAL the credentials secret's user must be 1-32 characters
tidb-server restarts with FATAL the credentials secret's user must be 1-32 characters
RELEASE_NAME-server restarts repeatedly and its logs contain:'db' must be 1-64 characters and not end with a space.Cause: the user or db key in the credentials secret is outside TiDB’s limits. The servers stop before the cluster bootstraps, so nothing is created with a passwordless root.Fix: write the secret back with a valid value (see Rotating Credentials for the cpln apply shape), then force a redeployment:TiDB servers log WARNING root accepts an EMPTY password
TiDB servers log WARNING root accepts an EMPTY password
rootPassword is empty.Fix: make sure the credentials secret holds a non-empty rootPassword and keep autoCreateDatabase.deployInitWorkload: true; the init job’s next run sets root’s password from the secret. Or set it yourself with ALTER USER 'root'@'%' IDENTIFIED BY 'YOUR-ROOT-PASSWORD'; and store the same value in the secret.helm install fails because a snapshots schedule runs more often than hourly
helm install fails because a snapshots schedule runs more often than hourly
tidb: volumeset.tikv.snapshots.schedule ... must be a 5-field cron with a single fixed minute (snapshots cannot run more often than hourly) (or the same for volumeset.pd).Cause: volume snapshots can run at most once an hour.Fix: use a schedule with one fixed minute, such as "0 3 * * *", or "" to turn snapshots off.A GCS restore fails with You should provide gcs.credentials-file
A GCS restore fails with You should provide gcs.credentials-file
br restore full from a GCS backup fails within seconds with You should provide '--gcs.credentials-file' when '--send-credentials-to-tikv' is true.Cause: by default br tries to send its own credentials to TiKV; on this template TiKV reads the bucket with the release’s identity instead.Fix: add --arg "--send-credentials-to-tikv=false" to the restore command, as in Restoring a Backup.helm upgrade fails at render saying a location sets replicas
helm upgrade fails at render saying a location sets replicas
tidb: location 'LOCATION_NAME' sets replicas, which 2.1.0 SPLIT into tikvReplicas ... and serverReplicas.Cause: your values file still uses the 2.0.0 replicas key. 2.1.0 sets TiKV nodes and SQL servers separately.Fix: replace replicas: N with tikvReplicas: N and serverReplicas: N in every locations entry. See Upgrading from 2.0.0.helm install fails with proxysql.enabled requires autoCreateDatabase.enabled
helm install fails with proxysql.enabled requires autoCreateDatabase.enabled
tidb: proxysql.enabled requires autoCreateDatabase.enabled.Cause: ProxySQL authenticates clients with the credentials from the secret named by autoCreateDatabase.credentialsSecretName, which is only wired in when autoCreateDatabase.enabled is true.Fix: set autoCreateDatabase.enabled: true with a valid credentials secret, or leave proxysql.enabled: false.Queries through ProxySQL fail intermittently with ERROR 1273
Queries through ProxySQL fail intermittently with ERROR 1273
RELEASE_NAME-server directly, but through RELEASE_NAME-proxysql some queries fail with ERROR 1273 ... latin1_swedish_ci.Cause: the client requests a latin1 charset. TiDB accepts that on a direct connection but rejects it when ProxySQL applies the client charset.Fix: connect with utf8mb4. Modern drivers default to it; for the mysql command-line client pass --default-character-set=utf8mb4.A client in another GVC location cannot connect
A client in another GVC location cannot connect
RELEASE_NAME-server.GVC_NAME.cpln.local:4000, while clients in other locations work.Cause: the client runs in a GVC location not listed in locations. Clients reach only the TiDB servers (and ProxySQL replicas) in their own location.Fix: run the client in a listed location, or add its location to locations and upgrade.helm install or upgrade fails at render naming a REMOVED key
helm install or upgrade fails at render naming a REMOVED key
tidb: exposeServer was REMOVED in 2.0.0, the gvc values key was REMOVED, devMode or autoCreateDatabase.database was REMOVED.Cause: your values file still carries a key that 2.0.0 removed. The guards fire on the key’s presence, even when it is set to false.Fix: delete the key and use its replacement from the list in Upgrading from 1.x. If this was an attempt to upgrade a 1.x release in place, stop — that path destroys the 1.x GVC. Install a new release instead.helm install fails with backup.location is not one of locations
helm install fails with backup.location is not one of locations
tidb: backup.location 'aws-us-west-2' is not one of locations (aws-us-east-1).Cause: the backup cron runs only in backup.location, which must be one of your locations.Fix: set backup.location to a location you configured, preferably the one nearest your bucket.Clients cannot connect after switching internal access to workload-list
Clients cannot connect after switching internal access to workload-list
RELEASE_NAME-server.GVC_NAME.cpln.local:4000 after setting internal_access.server.type: workload-list.Cause: the client workload is missing from internal_access.server.workloads, or the change has not finished taking effect yet.Fix: add the client as //gvc/GVC_NAME/workload/WORKLOAD_NAME, upgrade, and allow several minutes. You never need to list this release’s own workloads — they are always included.The backup job exits immediately after upgrading TiDB
The backup job exits immediately after upgrading TiDB
RELEASE_NAME-tidb-backup runs fail right after images.* was bumped, and the br output refuses the cluster version.Cause: br must match the cluster version; from v8.5.7 it enforces the check even with --check-requirements=false.Fix: bump backup.image to the same TiDB version as images.* and upgrade.The init job keeps running every five minutes
The init job keeps running every five minutes
RELEASE_NAME-tidb-db-init shows a new run on every tick of autoCreateDatabase.schedule, each logging Database already initialized. Exiting.Cause: expected. The job is a backstop cron in the first entry of locations that fast-exits once the database exists.Fix: none required. To remove it, set autoCreateDatabase.deployInitWorkload: false and upgrade.Important Notes
- Your application must retry failed connections and statements — without it, every upgrade and replica restart shows up as errors in your app. Retry with a short backoff for 10–15 seconds, make retried writes idempotent and use a 60-second client timeout; see Scaling and Availability.
- Root has a password from the start only when
autoCreateDatabase.enabledistrue(the default). With it off, root starts with no password — set one withALTER USERbefore clients can reach the cluster. - Each TiDB server start makes one root login attempt with an empty password, to confirm root is protected before serving. If you set
FAILED_LOGIN_ATTEMPTSon root, set it above your total number of TiDB servers, or restarting them all locks root. - Upgrading from 2.1.0 restarts every workload once — on the one-PD-and-TiKV-per-location layout, writes pause for about 75 seconds. Check first that root refuses an empty password; see Upgrading from 2.1.0.
- Never
helm upgradea 1.x release onto 2.x — it deletes the GVC the 1.x chart created and everything in it. Install a new release: Upgrading from 1.x. - Create the credentials secret before installing. Without it the deployment wedges silently; the only diagnostic is
status.versions[].messagefromcpln workload get-deployments. - Upgrading from 2.0.0 needs one values change: replace each location’s
replicaswithtikvReplicasandserverReplicas. See Upgrading from 2.0.0. - The GVC must contain every location you list, and may contain more. A missing location is not caught at install: PD exits with
FATAL: locations declared in values are not in GVC .... - Run clients in a listed location. Clients reach only the TiDB servers in their own location; use
serverReplicas: 2or more to keep a location serving through a server failure. - Surviving a location loss needs your application in at least 2 locations — see Scaling and Availability.
- PD’s replication factor is fixed when the cluster first bootstraps (TiKV node count, capped at 3). Start with at least 3 TiKV nodes if you ever want 3-way replication.
- Restore into a new, empty release whose
backupsection points at the same provider, bucket and cloud account. A full restore brings the source cluster’s users and root password with it; see Restoring a Backup. - Volume snapshots protect single volumes, not the cluster. Use a
brbackup to restore a whole cluster. - Keep
backup.imageandimages.*on the same TiDB version.brrefuses a version mismatch. - Through ProxySQL, connect with a utf8mb4 charset — a latin1 client fails intermittently with
ERROR 1273. - There is no public access to the MySQL port. Reach tidb-server over internal GVC DNS or
cpln port-forward RELEASE_NAME-server 4000:4000 --gvc GVC_NAME. - Release names must be unique per org — secrets and policies are org-wide, so two releases with the same name collide even in different GVCs.
- Credentials apply on first initialization only. Rotate with
ALTER USERinside TiDB first, then update the secret, then force a redeployment of tidb-server (and ofRELEASE_NAME-proxysqlwhen enabled). - Switch backup providers with a fresh install, not an upgrade — the identity keeps the old cloud-account binding.