>
Open Source

TiDB gave me a distributed MySQL on my laptop in fifteen minutes

I have been the person explaining to a junior engineer why their beautifully normalised MySQL schema will not survive Black Friday, and I have been the junior engineer who built that schema in the first place. Both sides are exhausting. So when someone told me PingCAP’s TiDB speaks the MySQL wire protocol (the byte-level conversation your client and server use to exchange queries and results) but spreads reads and writes across nodes out of the box, my first instinct was suspicion. My second was to actually try it. Here is what happened on a fresh Ubuntu box, with no magic.

The claim is bold. Most “distributed” databases want you to learn a new query dialect, swap drivers, or rewrite half your ORM (object-relational mapper, the layer that maps database rows to language objects). TiDB says: keep your mysql client, keep your SQL, keep your connection strings. The only change is the port number. That is a much smaller migration story than swapping Postgres for CockroachDB, and it is the reason I keep coming back to TiDB when people ask me what to do about a single-node MySQL bottleneck.

What TiDB actually is, without the marketing

TiDB is three programs pretending to be one database:

  • TiDB, the SQL front-end that parses, plans, and runs queries
  • TiKV, a distributed key-value store that holds the rows
  • PD, the placement driver that decides where data lives and moves it around

When you INSERT INTO users ..., the TiDB layer turns your statement into key-value operations and writes them into TiKV across multiple machines. When you SELECT, the same layer asks PD which nodes own the relevant ranges and gathers the rows. To your application, none of this is visible. The MySQL client thinks it is talking to a 5.7 server. TiDB 8.5, the current stable at the time of writing, even handles most of the weirder MySQL-isms like AUTO_INCREMENT, generated columns, and the usual string functions.

The architecture matters because it explains the trade-offs. There is no shared disk, no NFS (network file system) mount, no replication trick from the 1990s. Each component is a normal Linux process. You can run them on one box for testing or on twenty boxes for production, and the SQL you write does not change.

Installing TiUP, the package manager you didn’t know you needed

The PingCAP team ships TiDB through a tool called TiUP. Think of it like npm or apt-get, but for an entire database stack. TiUP knows which versions of TiDB, TiKV, and PD are compatible, downloads them on demand, and lays out the binaries in your home directory.

On Ubuntu, Debian, RHEL, or Rocky Linux, the install is a one-liner:

curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh

The flags matter. --proto '=https' blocks any downgrade to plain HTTP. --tlsv1.2 enforces a modern TLS (Transport Layer Security, the encryption protocol that replaced SSL) baseline. -sSf is silent on success, shows errors, and fails on HTTP errors. Together they are the curl flags you should be using by reflex for any install script, but most people don’t.

When the script finishes, tiup lands in ~/.tiup/bin. Reload your shell so the new PATH (the list of directories your shell searches for executables) takes effect:

source ~/.bashrc    # or source ~/.zshrc on Zsh
tiup --version

If tiup is still “command not found,” your shell did not pick up the PATH change. Open a new terminal or add export PATH=$HOME/.tiup/bin:$PATH to your rc file manually. I have hit this on fish and nushells more times than I care to admit.

Starting a playground cluster

For local learning and quick experiments, TiUP ships a playground command that boots a single-node cluster with TiDB, TiKV, PD, and TiFlash (the columnar engine for analytics queries) all in one process tree. It is the fastest way to find out whether TiDB fits your workload without standing up three servers.

tiup playground

First run takes a few minutes because TiUP downloads every component. Subsequent runs are seconds. When the cluster is up, you will see a banner pointing at:

  • MySQL port: 4000 (not 3306)
  • Dashboard: http://127.0.0.1:2379/dashboard
  • Grafana: http://127.0.0.1:3000

That port difference is the first trap. Every “TiDB won’t connect” issue I have debugged was a MySQL client defaulting to 3306 against a TiDB server listening on 4000. If you are running TiDB on a remote box and want clients from other machines to reach it, pass --host 0.0.0.0 and open port 4000 in the firewall:

## Ubuntu / Debian (UFW)
sudo ufw allow 4000/tcp

## RHEL / Rocky (firewalld)
sudo firewall-cmd --permanent --add-port=4000/tcp
sudo firewall-cmd --reload

Without that, your laptop cannot see the cluster even if ping works.

Connecting with the MySQL client you already have

Because TiDB speaks the MySQL protocol, you do not need a TiDB-specific client. The standard mysql CLI (command-line interface) from MySQL or MariaDB is enough:

## Ubuntu / Debian
sudo apt install mysql-client -y

## RHEL / Rocky
sudo dnf install mysql -y

Then point it at the playground:

mysql --host 127.0.0.1 --port 4000 -u root

There is no password in playground mode. If you see the mysql> prompt, you are inside a distributed SQL database pretending to be a single MySQL server. That is the whole pitch.

Running the first real queries

Now the moment of truth. Can you write normal SQL and have it work?

CREATE DATABASE workshop;
USE workshop;

CREATE TABLE servers (
  id INT PRIMARY KEY,
  hostname VARCHAR(50),
  role VARCHAR(20)
);

INSERT INTO servers VALUES
  (1, 'web01', 'frontend'),
  (2, 'db01',  'backend'),
  (3, 'cache01', 'redis');

SELECT * FROM servers;

You will get the same tabular output you would from MySQL. The data is being written across TiKV regions under the hood (TiKV splits data into roughly 96 MB chunks called regions and rebalances them automatically), but you do not see that until you look at the dashboard.

A few details that surprised me the first time:

  • AUTO_INCREMENT works, but TiDB allocates IDs in chunks of 30000 by default to avoid making every INSERT a coordination round-trip. If your application depends on monotonically increasing IDs with no gaps, you need to set AUTO_ID_CACHE 1.
  • Generated columns (GENERATED ALWAYS AS ...) work in 8.x. They did not in early 5.x releases.
  • Foreign keys with cascading actions are still flagged as experimental in 8.5. The MySQL community treats them as gospel, so this is the gap that will bite you if you migrate a legacy schema unchanged.

What this looks like in production

The playground is for learning. Real production means tiup cluster deploy with a topology file that names which servers run which component. The topology YAML (a plain-text config format) is the only place where you decide:

  • How many TiDB servers (typically 2 or 3 behind a load balancer for SQL ingress)
  • How many TiKV servers (3, 5, or more for storage and replication)
  • How many PD servers (3 for a quorum, or 1 for very small clusters)

TiUP then SSHes into each box, drops the right binaries, writes systemd unit files, and starts the services. Recovery, scaling, and rolling upgrades are all tiup cluster subcommands. The operational model is closer to running an Elasticsearch cluster than running MySQL, which is the second-biggest mental adjustment for teams coming from single-node MySQL.

You will also want to know how to drive systemctl (the Linux service manager) on these boxes, how to read journalctl logs (the systemd log viewer), and how to set up backups with BR (TiDB’s Backup & Restore tool, which ships snapshot and log-replay modes). None of that is exotic, but if your team has only ever run service mysqld restart, plan a week of learning.

Trade-offs

TiDB is not a drop-in replacement for MySQL in every situation. Here is what I would tell past me before betting a migration on it:

  • Latency overhead. A simple point query (a lookup by primary key) takes about 1.2 to 1.8x as long on TiDB as on MySQL on the same hardware, because of the extra network hop to PD and the key-value translation layer. For analytical queries that scan millions of rows, TiDB is often faster because of TiFlash’s columnar engine, but for OLTP (online transaction processing, the fast short-query workload that drives most apps) you trade a little latency for horizontal scale.
  • No foreign key cascades. Cascading deletes and updates are still experimental. If your schema leans heavily on them, expect to refactor or wrap them in application logic.
  • Operational complexity. One MySQL process is easier to operate than TiDB + TiKV + PD. For a single 500 GB database on one beefy box, MySQL is still the right answer. TiDB starts to pay off when you need to scale writes beyond a single node, not before.
  • TiUP ties you to PingCAP’s release cadence. Version compatibility is enforced by TiUP, which is good for stability but means you cannot casually run a custom-compiled TiKV without rebuilding the whole toolchain.
  • RHEL 7 is gone. TiDB 8.4 and later dropped RHEL 7 support. If your fleet still has RHEL 7 boxes, this is a forcing function to upgrade.

For my money, TiDB is the right pick when you have outgrown a single MySQL writer but are not ready to rewrite your application for Postgres, CockroachDB, or Aurora. The migration story is the smallest of the lot, and the playground gets you to “real query” in fifteen minutes flat.

What I would tell past me

If you are about to try TiDB, here is the order that will save you the most time:

  • Start with tiup playground on your laptop. Do not stand up a three-node cluster until you have written and torn down the playground twice.
  • Test your real workload, not a synthetic benchmark. TiDB’s latency profile is different from MySQL’s, and the difference matters more for your slowest queries than for your median ones.
  • Read the dashboard. The TiDB dashboard at port 2379 shows slow queries, region distribution, and lock contention. Treat it like the SHOW PROCESSLIST page you wish MySQL had.
  • Keep your backup story separate. Use BR (TiDB Backup & Restore) for full snapshots and the TiDB binlog (binary log, the record of every write the database ships to replicas) for point-in-time recovery. Do not try to back up TiKV directly; it is a moving target.
  • Do not skip the firewall. A playground cluster on --host 0.0.0.0 with port 4000 wide open on a cloud VM is a public MySQL you did not mean to deploy.

TiDB is not magic. It is a distributed SQL database that does the boring things well and lets you keep the MySQL muscle memory. If your bottleneck is a single MySQL writer, that is a trade worth taking.

Leave a comment