This guide is the operational and architectural reference for TiDB, the open-source distributed SQL database by PingCAP. It is written for administrators, SREs, architects, and developers who deploy, configure, secure, operate, and extend TiDB. Every fact here is derived directly from the source at commit 5e0c630.
It covers the system architecture, a complete configuration reference for tidb-server, security hardening, operations (startup, shutdown, monitoring, backup), and a deep dive into the internals — the DDL job engine, the Distributed eXecution Framework (DXF), and the code layout — sufficient for a reader to reason about, extend, or replicate the system.
Note
Scope of this repository.
pingcap/tidbis the SQL layer plus the ecosystem tools (BR, TiDB Lightning, Dumpling). The distributed KV store TiKV, the cluster controller PD (Placement Driver), and the columnar engine TiFlash are separate projects that TiDB communicates with over gRPC. This guide documents how TiDB uses them, not their internals.
Table of Contents
- Executive Summary
- Architecture
- System Requirements
- Configuration Mastery
- Security
- Operations
- Backup, Restore & Disaster Recovery
- Observability
- Internals: How TiDB Works
- Repository Structure
- Code Quality & Conventions
- Troubleshooting & Diagnostics
- Potential Improvements
- Quick Reference
1. Executive Summary
TiDB separates compute from storage:
tidb-server— a stateless SQL engine. It terminates MySQL-protocol connections, parses and optimizes SQL, and executes plans by issuing key-value and coprocessor requests to the storage layer. Because it holds no durable state, you scale SQL throughput by adding moretidb-serverinstances behind a load balancer, and any instance can fail without data loss.- TiKV — a distributed, transactional, Raft-replicated key-value store. It holds the actual data, sharded into "regions" and replicated for high availability.
- PD (Placement Driver) — the cluster brain: it allocates timestamps (the global clock for MVCC/transactions), stores cluster metadata, and schedules region placement and balancing.
- TiFlash (optional) — a columnar replica of selected tables, kept in sync from TiKV, for analytical (OLAP) queries. This is what makes TiDB HTAP.
Key operational properties:
| Property | Mechanism |
|---|---|
| Strong consistency | Raft majority commit in TiKV; global timestamps from PD |
| ACID transactions | Percolator-style two-phase commit; optimistic and pessimistic modes |
| Online schema change | Asynchronous, job-based DDL with a cluster-wide schema-version protocol |
| Horizontal scale | Add tidb-server (compute) and TiKV (storage) independently, online |
| MySQL compatibility | MySQL 8.0 wire protocol, error codes, system variables, metadata schemas |
2. Architecture
2.1 Cluster topology
┌──────────────────────────────┐
MySQL clients ──▶│ Load balancer (L4/L7) │
└───────────────┬──────────────┘
│ MySQL protocol :4000
┌────────────────────────────────┼────────────────────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ tidb-server │ │ tidb-server │ ... (stateless) │ tidb-server │
│ :4000 SQL │ │ :4000 SQL │ │ :4000 SQL │
│ :10080 HTTP│ │ :10080 HTTP│ │ :10080 HTTP│
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ gRPC (KV + coprocessor) │ │
└────────────────┬───────────────┴─────────────────┬───────────────┘
▼ ▼
┌───────────────┐ ┌───────────────┐
│ PD │ timestamps, │ TiKV nodes │ row store
│ :2379 /2380 │ metadata, │ :20160 │ (Raft groups)
│ (Raft, 3+) │ scheduling │ (3+ replicas)│
└───────────────┘ └───────┬───────┘
│ Multi-Raft Learner
▼
┌───────────────┐
│ TiFlash │ columnar
│ (optional) │ (HTAP/OLAP)
└───────────────┘
2.2 The tidb-server process
tidb-server is a single Go binary whose main() (cmd/tidb-server/main.go) performs a deterministic startup sequence:
- Parse flags (
initFlagSet) and load config (config.InitializeConfig), merging file + flags. - Register store drivers (
registerStores) — TiKV, MockTiKV, and the embedded UniStore. - Initialize globals — logging (
setupLog), metrics (setupMetrics), memory hooks, CPU profiling, extensions, statement-summary, tracing. - Create the store, DDL owner manager, and Domain (
createStoreDDLOwnerMgrAndDomain):- Connect to the store (
kvstore.MustInitStorage). - Verify the PD/TiDB kernel type matches (classic vs next-gen) — a mismatch aborts startup.
- Start the DDL owner manager (
ddl.StartOwnerManager). - Bootstrap a session (
session.BootstrapSession) which loads/creates the system schema and returns the Domain.
- Connect to the store (
- Create the SQL server (
createServer) — wraps the storage with aTiDBDriver, builds the MySQL-protocolserver.Server, and attaches background handles (expensive-query killer, memory-usage alarm, server-memory-limit enforcement). - Install signal handlers for graceful shutdown and run (
svr.Run(dom)).
2.3 The Domain
The Domain (pkg/domain) is the per-instance hub that ties together:
- the InfoSchema (the in-memory snapshot of all databases/tables/indexes) and its synchronizer,
- the DDL subsystem and its owner election,
- statistics handling, the timer/TTL subsystems, plan replayer, and the info-syncer that publishes this server's presence to the cluster.
Every tidb-server has exactly one Domain; it is the root object from which the executor, planner, and session layers obtain schema and cluster state.
2.4 Request lifecycle
A SQL statement flows: MySQL protocol (pkg/server) → session (pkg/session) → parser (pkg/parser, builds an AST) → planner (pkg/planner, logical + physical optimization, pkg/planner/core) → executor (pkg/executor, the volcano-style operator tree) → distsql / store (pkg/distsql, pkg/store) which pushes coprocessor requests to TiKV and reads back results. Expression evaluation lives in pkg/expression; type handling in pkg/types; row/key encoding in pkg/tablecodec and pkg/kv.
2.5 Kernel types: classic vs next-gen
The source distinguishes two kernel types (pkg/config/kerneltype):
- Classic — the traditional architecture (PD + TiKV; no distributed file system).
- Next-gen — a multi-tenant, keyspace-aware architecture that adds a TiKV-Worker component and S3-compatible DFS (distributed file system) integration. Next-gen requires a
--keyspace-name(or standby mode) and forbids manual version overrides.
A tidb-server checks at startup that its kernel type matches PD's; a mismatch is a fatal kernel type mismatch error.
3. System Requirements
3.1 Build
| Item | Requirement |
|---|---|
| Go | 1.25.10 (root module); 1.25 for pkg/parser |
| Build system | make (targets: make server, make build_for_br_integration_test, etc.) |
| Platform | Linux/macOS for full functionality; Windows lacks secure bootstrap |
3.2 Runtime ports
| Component | Port(s) | Purpose |
|---|---|---|
tidb-server SQL |
4000 |
MySQL protocol |
tidb-server status |
10080 |
HTTP: health, metrics, schema, pprof |
| PD | 2379 (client), 2380 (peer) |
Timestamps, metadata, scheduling |
| TiKV | 20160 (service), 20180 (status) |
KV storage |
| TiKV-Worker (next-gen) | 19000 |
Coprocessor offload |
3.3 External storage (for BR / Lightning / DFS)
TiDB's tooling integrates with object storage via vendored SDKs (from go.mod): Amazon S3 (aws-sdk-go-v2), Google Cloud Storage (cloud.google.com/go/storage), Azure Blob (azure-sdk-for-go), and Aliyun OSS. Storage URLs use schemes s3://, gcs://, azure://, local://.
4. Configuration Mastery
tidb-server is configured by a TOML file (--config) deserialized into the Config struct (pkg/config/config.go). Command-line flags override matching keys. This section documents the structure and the load-bearing defaults; defaults are the constants defined alongside the struct.
Tip
Validate before deploying:
tidb-server --config tidb.toml --config-check. Add--config-strictin CI to fail on unknown keys. Unknown keys are otherwise warned-about, not fatal.
4.1 Top-level keys
| TOML key | Default | Meaning |
|---|---|---|
host |
0.0.0.0 |
SQL bind address |
advertise-address |
(derived) | Address advertised to the cluster |
port |
4000 |
SQL port |
store |
unistore |
tikv, unistore, or mocktikv |
path |
/tmp/tidb |
Storage path, or PD endpoints when store=tikv |
socket |
/tmp/tidb-{Port}.sock |
Unix socket |
lease |
45s |
Schema lease — interval for schema-version sync. Do not change casually. |
token-limit |
1000 |
Max concurrent executing sessions (cap 1048576) |
split-table |
— | Pre-split a region per new table to avoid hotspots |
temp-dir |
/tmp/tidb |
Temp directory |
tmp-storage-path |
(encoded per host/port) | Spill-to-disk location for large queries |
tmp-storage-quota |
— | Byte quota for spill storage; startup fails if it exceeds capacity |
max-index-length |
3072 |
Max index length in bytes (MySQL-compatible; max 12288) |
index-limit |
64 |
Max indexes per table (max 512) |
table-column-count-limit |
1017 |
Max columns per table (max 4096) |
max-allowed-packet |
67108864 (64 MiB) |
Max packet size (starter mode) |
new_collations_enabled_on_first_bootstrap |
— | Enables new collation framework (first-bootstrap only) |
enable-table-lock |
— | Enable LOCK TABLES support |
enable-global-kill |
— | Cluster-wide KILL <connid> |
graceful-wait-before-shutdown |
0 |
Seconds to report unhealthy before shutdown (drains LBs) |
repair-mode / repair-table-list |
false / — | Table-meta repair mode |
deploy-mode / keyspace-name |
— | Next-gen deployment/keyspace selection |
4.2 Config sections
The Config struct nests these sections (each a TOML [section]):
| Section | Purpose | Notable keys |
|---|---|---|
[log] |
Logging | level, format, slow-query-file, file.filename, file.max-days, file.max-size |
[instance] |
Instance-scoped settings (the modern home for many options) | tidb_enable_ddl, max_connections, tidb_general_log, tidb_slow_log_threshold, tidb_memory_usage_alarm_ratio, plugin_load, plugin_dir |
[security] |
TLS, auth, bootstrap | ssl-ca, ssl-cert, ssl-key, cluster-ssl-ca/cert/key, secure-bootstrap, skip-grant-table, disconnect-on-expired-password, auto-tls |
[status] |
Status/HTTP server | report-status, status-host, status-port, metrics-addr, metrics-interval |
[performance] |
Resource tuning | max-procs, server-memory-quota, txn-total-size-limit, txn-entry-size-limit, stats-lease, gogc, cross-join, distinct-agg-push-down, enforce-mpp |
[prepared-plan-cache] |
Prepared-statement plan cache | enabled, capacity, memory-guard-ratio |
[pd-client] |
PD client tuning | timeouts, retry, request concurrency |
[tikv-client] |
TiKV client tuning | grpc-connection-count, commit-timeout, region-cache-ttl, store-liveness-timeout, copr-cache |
[pessimistic-txn] |
Pessimistic locking | max-retry-count, deadlock-history-capacity, constraint-check-in-place-pessimistic |
[isolation-read] |
Engine routing | engines (e.g. ["tikv","tiflash"]) |
[proxy-protocol] |
PROXY protocol | networks, header-timeout, fallbackable |
[opentracing] |
Jaeger tracing | enable, sampler/reporter settings |
[top-sql] |
Top-SQL CPU attribution | receiver-address |
[transaction-summary] |
Transaction recording | transaction-summary-capacity, transaction-id-digest-min-duration |
[experimental] |
Experimental flags | gated features |
[standby] |
Standby/serverless activation | standby, activation-timeout, max-idle-seconds |
4.3 Key tuning defaults (from source constants)
| Constant | Default | Notes |
|---|---|---|
DefSchemaLease |
45s |
Schema-version lease |
DefTxnEntrySizeLimit |
6 MiB |
Single-entry size cap; hard max 120 MiB |
DefTxnTotalSizeLimit |
100 MiB |
When left at default, a large per-session memory tracker effectively governs txn size instead |
DefMemoryUsageAlarmRatio |
0.8 |
Fraction of memory that triggers an alarm dump |
DefExpensiveQueryTimeThreshold |
60s |
Logs queries exceeding this |
DefExpensiveTxnTimeThreshold |
600s |
Logs long-running transactions |
DefDDLSlowOprThreshold |
300ms |
Logs slow DDL operations |
MaxLogFileSize |
4096 MB |
Per-log-file cap |
DefMaxAllowedPacket |
64 MiB |
— |
4.4 Deprecated / moved options
The source maintains a sectionMovedToInstance map: several options that historically lived at the top level or in [log]/[performance]/[plugin] have moved to the [instance] section and/or become system variables. Examples:
| Old config key | New home |
|---|---|
run-ddl |
[instance] tidb_enable_ddl |
max-server-connections |
[instance] max_connections |
check-mb4-value-in-utf8 |
[instance] tidb_check_mb4_value_in_utf8 |
log.enable-slow-log |
[instance] tidb_enable_slow_log |
log.slow-threshold |
[instance] tidb_slow_log_threshold |
performance.force-priority |
[instance] tidb_force_priority |
plugin.load / plugin.dir |
[instance] plugin_load / plugin_dir |
TiDB still reads the old keys for upgrade compatibility but logs them as deprecated. Migrate to the new locations.
Important
Many runtime behaviors are governed by system variables (
SET GLOBAL tidb_...), not config keys — they are stored in the cluster and persist across restarts. Use--initialize-sql-fileto set GLOBAL variables on first bootstrap, since they are not read from the config file. Config keys generally set process/instance defaults; system variables set cluster-wide behavior.
5. Security
TiDB's security surface spans network TLS, authentication, authorization, the status port, and an optional Security Enhanced Mode.
5.1 Transport security (TLS)
There are two independent TLS channels, configured separately:
| Channel | Config keys | Flags |
|---|---|---|
| Client ↔ TiDB (SQL) | [security] ssl-ca, ssl-cert, ssl-key |
--sql-ca, --sql-cert, --sql-key |
| TiDB ↔ TiKV/PD (cluster) | [security] cluster-ssl-ca, cluster-ssl-cert, cluster-ssl-key |
--cluster-ca, --cluster-cert, --cluster-key |
The startup code enforces that cert and key are set together, and that a ca requires both. Corresponding environment variables exist (SQL_CA, SQL_CERT, SQL_KEY, CLUSTER_CA, …) for containerized deployments.
Caution
Enable cluster TLS in any multi-host deployment. Without it, TiDB↔TiKV↔PD gRPC traffic — including data and timestamps — crosses the network in plaintext.
5.2 Authentication & bootstrap
- Insecure bootstrap (default):
--initialize-insecure=truecreates arootaccount with an empty password. Convenient for testing, unsafe for production. - Secure bootstrap:
--initialize-secure=trueuses Unix-socket authentication for the initial setup (not available on Windows). - Skip-grant mode:
[security] skip-grant-table(or theSkipWithGrantpath) disables privilege checks entirely — an emergency-recovery escape hatch only. Never run this exposed. - Password lifecycle:
disconnect-on-expired-password(default true) disconnects clients with expired passwords; disabling it puts such sessions into a sandbox mode. Errorsprivilege:1862 Your password has expiredsurface this. - LDAP / JWT / auth tokens: Pluggable auth methods exist (
pkg/privilege/privileges/ldap, JWT vialestrrat-go/jwx), including a configurable auth-token refresh interval (DefAuthTokenRefreshInterval = 1h).
5.3 Authorization
Privileges follow the MySQL model (pkg/privilege): GRANT/REVOKE, user@host matching, roles, and dynamic privileges. Access failures map to MySQL codes (1045 access denied, 1142 command denied, 1141 no such grant, 3530 role not granted). Privilege data lives in the mysql.* system tables and is cached in the Domain.
5.4 Status port hardening
The status HTTP server (:10080) exposes profiling (/debug/pprof/*), a diagnostics bundle (/debug/zip), config (/config), and schema introspection. Restrict it:
- Bind
status-hostto an internal interface, not0.0.0.0, in production. - Firewall port
10080from client networks. - Set
skip-register-to-dashboardif you do not want a server advertised to TiDB Dashboard.
5.5 Security Enhanced Mode (SEM)
TiDB ships a Security Enhanced Mode (pkg/util/sem, set up via setupSEM) that, when enabled, restricts powerful operations and hides sensitive system-table contents even from privileged users — useful for managed/multi-tenant deployments where the operator must protect data from root.
5.6 Log redaction
Both tidb-server and BR support log redaction (redact-info-log, the --redact collect-log subcommand) to strip sensitive values from logs before they leave the host — important when shipping logs to third parties.
5.7 Handling untrusted SQL workloads
Resource-control features (resource groups, runaway-query detection under pkg/resourcegroup) let you cap the resources a tenant or query can consume, mitigating noisy-neighbor and accidental-DoS risks from untrusted SQL.
6. Operations
6.1 Starting a production instance
tidb-server \
--store=tikv \
--path="pd1:2379,pd2:2379,pd3:2379" \
--config=/etc/tidb/tidb.toml \
--host=0.0.0.0 --port=4000 \
--status=10080 \
--advertise-address="$(hostname -i)" \
--log-file=/var/log/tidb/tidb.log
Deployment checklist:
- [ ] PD endpoints reachable from this host
- [ ] Cluster TLS certs in place (
cluster-ssl-*) if multi-host - [ ]
advertise-addressset to a cluster-reachable IP (auto-derived ifhost=0.0.0.0) - [ ] Config validated (
--config-check) - [ ] Log directory writable; rotation configured (
log.file.max-days,max-size) - [ ]
tmp-storage-pathon a volume with adequate free space ≥tmp-storage-quota - [ ] Load balancer health-checks
GET /status
6.2 Graceful shutdown
On SIGTERM/SIGINT, tidb-server: closes the SQL server (svr.Close()), stops the resource manager, cleans up the Domain and storage, stops the CPU profiler, flushes logs, then exits. To drain connections gracefully, set graceful-wait-before-shutdown so the status endpoint reports unhealthy first and the load balancer stops sending new connections before the process stops accepting work.
Note
A
SIGINT-driven shutdown returns exit code130(128 + SIGINT) so deployment scripts can distinguish a forced/standby shutdown from a normal exit.
6.3 Rolling upgrades & online DDL during upgrade
Because DDL is owner-driven and version-synchronized, upgrades are rolling: replace tidb-server instances one at a time behind the load balancer. The source includes explicit machinery to pause user DDL while upgrading (design doc 2023-04-11-pause-user-ddl-when-upgrading.md) so schema changes don't race the bootstrap-version migration. Let the cluster finish its bootstrap upgrade before resuming heavy DDL.
6.4 Memory & OOM protection
TiDB has layered memory protection:
- Per-query / global trackers —
server-memory-quotaand the global memory tracker bound total query memory; queries spill totmp-storage-pathwhenEnableTmpStorageOnOOMis on. - Memory-usage alarm — at
memory-usage-alarm-ratio(default0.8) of available memory, TiDB writes an alarm + profile for diagnosis. - Server memory limit handle — a background goroutine (
ServerMemoryLimitHandle) enforcestidb_server_memory_limitby cancelling the most memory-hungry queries. - Expensive-query killer — queries exceeding
expensive-query-time-thresholdare logged and can be killed.
6.5 Resource control
Resource groups (pkg/resourcegroup) let you allocate Request Units (RUs) per workload and detect/limit "runaway" queries — essential for multi-tenant clusters. RU weighting is tunable via the [ru-v2] config (the source ships experimentally-fitted default weights in DefaultRUV2Config).
6.6 Time-to-live (TTL) tables
TiDB has a built-in TTL subsystem (pkg/ttl) — define a row-expiry policy on a table and background TTL workers delete expired rows on a schedule, governed by the timer framework (pkg/timer). This avoids external cron jobs for data-retention enforcement.
7. Backup, Restore & Disaster Recovery
The end-user mechanics of BR (br) are in the User Guide §8. This section covers the operational/DR posture.
7.1 Backup strategy
| Layer | Tool | Cadence |
|---|---|---|
| Periodic full snapshot | br backup full |
Daily/weekly to object storage |
| Continuous change capture | br log start (log backup) |
Always-on, streams to storage |
| Point-in-time recovery | br restore point |
On demand: base snapshot + log replay to a target TS |
The combination of a base full backup and a continuous log backup gives point-in-time recovery to any timestamp within the retention window.
7.2 BR internals worth knowing
- BR runs as a client that talks to PD/TiKV directly; during backup it disables its own memory-limit tuner because server memory is measured on the TiDB node, not the BR host (
br/cmd/br/cmd.go). - BR computes a memory limit for itself based on free memory (
calculateMemoryLimit) and starts a heap-dump-on-pressure monitor (BR_HEAP_DUMP_DIR, default/tmp/br_heap_dumps). - During backup BR sets
AdvertiseAddressto an unavailable IP and disables coprocessor caching so it doesn't pollute cluster state. br operatorprovides tidb-operator integration:prepare-for-snapshot-backup(pause GC/schedulers),base64ify, migration listing/applying, and checksum subcommands.
7.3 Verifying backups
br debug backupmeta validate --storage <url> # checks key ranges & rewrite rules
br debug checksum --storage <url> # recomputes & compares checksums
A failed verification raises BR:Backup:ErrBackupChecksumMismatch. Treat such a backup as unusable.
7.4 GC and backup safepoints
TiDB's garbage collection reclaims old MVCC versions. Backups coordinate with GC via safepoints so data needed by an in-progress backup isn't collected; a mis-set safepoint surfaces as BR:Backup:ErrBackupGCSafepointExceeded. Don't shorten the GC lifetime below your backup window.
8. Observability
8.1 Metrics
Every tidb-server exposes Prometheus metrics at GET /metrics (:10080). It can also push to a Pushgateway (--metrics-addr, --metrics-interval, default 15s; 0 disables). Metric definitions live in pkg/metrics; pre-built Grafana dashboards are generated from jsonnet in pkg/metrics/grafana.
8.2 Status / introspection API
The status server (pkg/server/http_status.go) is the operational control plane. Highlights:
| Endpoint | Use |
|---|---|
/status |
Health/version (load-balancer probe) |
/info, /info/all |
This node / whole cluster topology |
/schema, /schema/{db}/{table} |
Live schema introspection |
/ddl/history, /ddl/owner/resign |
DDL job history; force owner re-election |
/config |
Effective configuration |
/tables/{db}/{table}/regions |
Region layout (hotspot analysis) |
/regions/hot, /regions/meta |
Hot/region metadata |
/mvcc/key/{db}/{table}/{handle} |
Inspect MVCC versions of a row |
/debug/pprof/* |
Go profiling |
/debug/zip |
One-shot diagnostics bundle for support |
/dxf/task/active, /dxf/schedule/status |
Distributed-task framework state |
8.3 Logs
| Log | Config | Content |
|---|---|---|
| Server log | --log-file, [log] |
Operational events; level via -L |
| Slow-query log | --log-slow-query, tidb_slow_log_threshold |
Queries over the threshold; also in information_schema.slow_query |
| General log | --log-general, tidb_general_log |
Every statement (debugging only — high volume) |
8.4 In-SQL observability
- Top-SQL (
[top-sql]) attributes CPU to specific SQL digests. - Statement summary (
pkg/util/stmtsummary) aggregates per-digest latency/row stats, queryable viaINFORMATION_SCHEMA. - Continuous profiling integrates with Grafana Pyroscope (
PYROSCOPE_SERVER_ADDRESSenv var + related auth vars) and an internal CPU profiler. - Cluster tables —
information_schema.cluster_info,cluster_log,slow_query, and themetrics_schemaexpose cluster-wide state from any node.
9. Internals: How TiDB Works
This section is the developer/architect deep dive — enough to extend or reason about the system. It is grounded in the in-tree architecture notes under docs/agents/ and the package layout.
9.1 Online DDL: the job engine
TiDB DDL is job-based and owner-driven. A DDL SQL statement does not mutate schema in place; it becomes a persistent job that the cluster's single DDL owner schedules and runs through a state machine. Flow (docs/agents/ddl):
Session ─▶ DDLExec (pkg/executor/ddl.go)
─▶ DDL Executor (pkg/ddl/executor.go) converts AST → model.Job
─▶ JobSubmitter (pkg/ddl/job_submitter.go) allocates IDs, INSERTs into mysql.tidb_ddl_job, notifies owner
─▶ DDL Owner / jobScheduler (pkg/ddl/job_scheduler.go) dispatches to worker pools
─▶ Workers (pkg/ddl/job_worker.go) run job step-by-step, advancing schema states
─▶ Syncer (pkg/ddl/schemaver/syncer.go) bumps global schema version, waits for all nodes to sync (etcd)
─▶ job moved to history; submitting session unblocks
The schema-state machine for an index/column change is delete only → write only → reorganization → public. This staged progression — combined with the cluster-wide schema-version sync and the schema lease (45s) — is what makes DDL safe to run online while other nodes still serve the old schema. A reorg/backfill step (e.g. ADD INDEX) scans and writes data with checkpoints so it can resume after owner failover.
Warning
The most common mistake when extending TiDB is implementing DDL behavior directly in the executor layer (
pkg/executor), bypassing job persistence, the schema state machine, version sync, and MDL/lease safety. New DDL must go through the job framework.
Key system tables: mysql.tidb_ddl_job (queue), mysql.tidb_ddl_reorg (reorg progress), plus MDL (metadata-lock) tables. Inspect from SQL with ADMIN SHOW DDL [JOBS], or force owner re-election via POST /ddl/owner/resign.
9.2 Distributed eXecution Framework (DXF)
DXF (pkg/dxf) is TiDB's framework for running large work across all nodes instead of on a single tidb-server. It powers distributed ADD INDEX backfill and IMPORT INTO. Structure (docs/agents/dxf):
pkg/dxf/framework/proto— task/step/state enums.pkg/dxf/framework/storage— task & subtask persistence (the dist-task tables).pkg/dxf/framework/scheduler— owner-side scheduler that admits tasks, reserves slots, and advances steps. Runs only on the DDL owner node.pkg/dxf/framework/taskexecutor— node-side executor manager that runs subtasks on every node and reports progress.
Runtime: business logic submits a task → framework persists it → every node runs an executor-manager loop → the owner runs the scheduler loop that advances steps and dispatches subtasks → executors run subtasks and report state. Task rank (priority, create_time, id) drives both scheduling and preemption; slot reservation governs concurrency (MaxConcurrentTask).
To add a new distributed task type: define task/step enums (keeping step constants backward-compatible), implement a scheduler.Extension and a taskexecutor.Extension, and register both. A minimal skeleton lives in pkg/dxf/example.
9.3 IMPORT INTO and conflict handling
IMPORT INTO (a DXF app, pkg/dxf/importinto) has two paths:
- Local sort:
Init → Import → PostProcess → Done. - Global sort:
Init → EncodeAndSort → MergeSort → WriteAndIngest → CollectConflicts → ConflictResolution → PostProcess → Done.
On global sort, duplicate keys are detected and written to conflicted-rows/<task-id>/<subtask-id>-<uuid> — deliberately outside the task's cleanup path so they survive for inspection. If the in-memory conflict-handle set exceeds its bound (TooManyConflictsFromIndex), the final checksum verification is skipped. Cleanup (clean_up.go) switches the table mode back to normal, deletes task-scoped global-sort artifacts (but not the conflict rows), and, in next-gen, emits metering.
9.4 Transactions
TiDB implements Percolator-style two-phase commit over TiKV with global timestamps from PD. Both optimistic (conflicts detected at commit) and pessimistic (locks acquired during execution) modes are supported; the pessimistic path is tuned under [pessimistic-txn] (retry count, deadlock-history capacity, in-place constraint checks). Transaction size is bounded by txn-entry-size-limit (6 MiB default, 120 MiB hard max) and txn-total-size-limit. A deadlock-history ring buffer aids diagnosis (information_schema.deadlocks).
9.5 Query optimizer
The planner (pkg/planner, pkg/planner/core, ~2.7 MB of source — the single largest subsystem along with the executor and expression engine) performs logical optimization (rule-based: predicate pushdown, column pruning, join reordering) and physical optimization (cost-based, using statistics from pkg/statistics). A cascades-style optimizer (pkg/planner/cascades) is also present. Plan and execution can be inspected with EXPLAIN / EXPLAIN ANALYZE, the plan cache ([prepared-plan-cache]), SQL plan bindings (pkg/bindinfo), and plan replayer dumps (/plan_replayer/dump).
9.6 Storage abstraction
pkg/kv defines the transactional KV interface; pkg/store provides drivers — the real tikv driver (pkg/store/driver, wrapping tikv/client-go), the embedded unistore (pkg/store/mockstore/unistore), and a mock. pkg/tablecodec encodes rows and indexes into KV keys; pkg/distsql builds and dispatches coprocessor requests that push computation down to TiKV.
10. Repository Structure
The codebase is a large Go monorepo. The highest-signal directories (by size and importance):
| Path | Size¹ | Responsibility |
|---|---|---|
pkg/expression |
~3.9 MB | SQL expression & built-in function evaluation |
pkg/executor |
~3.3 MB | Physical operator execution (volcano model) |
pkg/ddl |
~3.0 MB | Online schema-change engine (job-based) |
pkg/planner/core |
~2.7 MB | Query optimizer (logical + physical) |
pkg/infoschema |
~627 KB | In-memory schema snapshot & sync |
pkg/session |
~597 KB | Session lifecycle, bootstrap, SQL entry |
dumpling/export |
~454 KB | Dumpling logical-export engine |
pkg/server |
~432 KB | MySQL protocol server + status HTTP API |
pkg/statistics |
~366 KB | Table statistics & auto-analyze |
pkg/ttl |
~368 KB | TTL (row-expiry) workers |
pkg/parser |
~298 KB | SQL parser (separate Go module) |
pkg/domain |
~264 KB | Per-instance hub (schema, DDL, stats, syncers) |
pkg/errno |
~234 KB | Error code definitions (MySQL-compatible) |
pkg/config |
~178 KB | Configuration struct & loader |
br/ |
— | Backup & Restore tool |
lightning/, pkg/lightning |
— | TiDB Lightning importer |
dumpling/ |
— | Dumpling exporter |
cmd/tidb-server |
— | The server main() entry point |
pkg/dxf |
— | Distributed eXecution Framework |
docs/design, docs/agents |
— | Design docs & internal navigation maps |
¹ Approximate source size of the HIGH-priority modules as triaged during analysis.
Entry points (func main): cmd/tidb-server/main.go, br/cmd/br/main.go, lightning/cmd/tidb-lightning/main.go, lightning/cmd/tidb-lightning-ctl, dumpling/cmd/dumpling/main.go, plus dev utilities under cmd/ (benchdb, benchkv, benchraw, importer, ddltest, mirror, pluginpkg) and tools/.
11. Code Quality & Conventions
- Language & style: Go 1.25, enforced by an extensive linter set (golangci-lint, revive, gosec, custom analyzers in
tools/). License headers are mandatory (checked by skywalking-eyes). - Error handling: Errors are namespaced
Component:Subsystem:ErrNameand auto-documented intoerrors.toml(3,623 lines) byerrdoc-gen. User-facing errors carry MySQL-compatible numeric codes (pkg/errno). - Testing: Heavy use of unit tests, integration tests (shell-driven under
br/tests,lightning/tests,dumpling/tests), and real-TiKV tests (tests/realtikvtest). Determinism is aided byfailpointinjection. There is even an LLM-assisted test harness (tests/llmtest). - Internal docs:
docs/agents/*provide "read-first" navigation maps for the trickiest subsystems (DDL, DXF, IMPORT INTO, planner) with the explicit rule that code is the source of truth and docs must be updated when they drift. - Build: Bazel and
makeare both supported; the parser is a separate Go module (pkg/parser/go.mod) replaced locally.
Note
The dependency set is large because the tooling integrates with many clouds (AWS/GCS/Azure/Aliyun SDKs), observability stacks (Prometheus, OpenTelemetry, Jaeger, Pyroscope), and storage engines (
cockroachdb/pebble,pingcap/badger). The core SQL path depends mainly ontikv/client-go,tikv/pd/client, andetcd.
12. Troubleshooting & Diagnostics
Diagnostic-first workflow
- Health:
curl :10080/statuson each node; checkinformation_schema.cluster_info. - Metrics: Grafana dashboards (from
pkg/metrics/grafana) or/metrics. - Bundle:
GET /debug/zipcollects config, schema, profiles, and recent logs into one archive for support. - Slow queries:
information_schema.slow_query+ the slow log. - DDL stuck?
ADMIN SHOW DDL JOBS; check the owner withADMIN SHOW DDL; inspectmysql.tidb_ddl_job.
Common operational errors
Error: kernel type mismatch
- Cause:
tidb-server's kernel type (classic/next-gen) disagrees with PD's. - Solution: Run a build/config matching the cluster's kernel type. Next-gen requires
--keyspace-name.
Error: invalid config: keyspace name or standby mode is required for nextgen tidb
- Cause: Next-gen kernel started without a keyspace or standby mode.
- Solution: Pass
--keyspace-name <name>(or run with--standby).
Error: value of [tmp-storage-quota] (...) exceeds the capacity of the [...] directory
- Cause: Spill-storage quota exceeds free space on the temp volume.
- Solution: Lower
tmp-storage-quota, movetmp-storage-path, or add disk.
Error: cannot set txn entry size limit larger than 120M
- Cause:
txn-entry-size-limitset above the 120 MiB hard cap. - Solution: Keep it ≤
120 MiB; restructure very large single writes.
Error: BR:Common:ErrFailedToConnect (failed to make gRPC channels)
- Cause: BR cannot reach PD/TiKV.
- Solution: Verify
--pdreachability and TLS material.
Error: admin:8223 data inconsistency in table ...
- Cause: Index/record mismatch detected by
ADMIN CHECK. - Solution: Freeze writes to the table, capture
/debug/zip, engage support; do not blindly rebuild.
Memory-usage alarm firing repeatedly
- Cause: Queries near
memory-usage-alarm-ratio(0.8) of available memory. - Solution: Set/lower
tidb_server_memory_limit, enable spill-to-disk, identify the offending query via the alarm's profile dump, add resource-group limits.
13. Potential Improvements
Observations drawn from the codebase that operators and contributors may weigh:
- Archived dependency cleanup.
go.modcarries areplaceforsourcegraph.com/sourcegraph/appdashwith a TODO noting the upstream is archived and should be removed. - Deprecated config keys persist. Several options remain at the top level only for upgrade compatibility (
EnableBatchDML,MemQuotaQuery,OOMAction,OOMUseTmpStorage, the moved-to-[instance]set). A future major version could drop them; operators should migrate now to avoid surprise. - Hidden but powerful subcommands.
br debugandbr operatorare marked hidden yet are load-bearing for support and tidb-operator. Clear external documentation of their contract would reduce reliance on reading source. - Large subsystems.
pkg/expression,pkg/executor,pkg/ddl, andpkg/planner/coreare each multi-megabyte. The in-treedocs/agents/*navigation maps are an effective mitigation; extending that pattern to the executor and expression engines would help new contributors. - Default insecure bootstrap. The default
--initialize-insecure=true(empty root password) is convenient but a foot-gun if a test config reaches production. Consider defaulting deployment tooling to secure bootstrap.
Note
These are framed from a single-snapshot reading of the source at
5e0c630; the TiDB roadmap (roadmap.md) and design docs (docs/design) reflect the maintainers' own prioritized direction.
14. Quick Reference
Ports
| Component | Port |
|---|---|
| TiDB SQL | 4000 |
| TiDB status/HTTP | 10080 |
| PD | 2379 / 2380 |
| TiKV | 20160 / 20180 |
| TiKV-Worker (next-gen) | 19000 |
Essential config keys
host = "0.0.0.0"
port = 4000
store = "tikv"
path = "pd1:2379,pd2:2379,pd3:2379"
lease = "45s" # schema lease — do not change casually
[log]
level = "info"
slow-query-file = "/var/log/tidb/slow.log"
[security]
ssl-ca = "/etc/tidb/certs/ca.pem"
ssl-cert = "/etc/tidb/certs/tidb.pem"
ssl-key = "/etc/tidb/certs/tidb-key.pem"
cluster-ssl-ca = "/etc/tidb/certs/ca.pem"
cluster-ssl-cert = "/etc/tidb/certs/tidb.pem"
cluster-ssl-key = "/etc/tidb/certs/tidb-key.pem"
[status]
status-port = 10080
metrics-addr = "pushgateway:9091"
[performance]
server-memory-quota = 0 # 0 = use system memory
Operational SQL
| Task | Statement |
|---|---|
| DDL owner & state | ADMIN SHOW DDL; |
| DDL jobs | ADMIN SHOW DDL JOBS; |
| Integrity check | ADMIN CHECK TABLE t; |
| Cluster nodes | SELECT * FROM information_schema.cluster_info; |
| Slow queries | SELECT * FROM information_schema.slow_query ORDER BY query_time DESC; |
| Deadlocks | SELECT * FROM information_schema.deadlocks; |
| TiFlash replica | ALTER TABLE t SET TIFLASH REPLICA 1; |
Diagnostic endpoints
URL (:10080) |
Use |
|---|---|
/status |
Health |
/info/all |
Cluster topology |
/config |
Effective config |
/ddl/history |
DDL job history |
/tables/{db}/{tbl}/regions |
Hotspot analysis |
/debug/zip |
Support bundle |
Tool entry points
| Binary | Source |
|---|---|
tidb-server |
cmd/tidb-server/main.go |
br |
br/cmd/br/main.go |
tidb-lightning |
lightning/cmd/tidb-lightning/main.go |
dumpling |
dumpling/cmd/dumpling/main.go |