TiDB on Ubuntu 24.04 on Azure User Guide
Overview
TiDB is an open-source distributed SQL database from PingCAP, licensed Apache-2.0. It separates compute from storage across three components:
- TiDB - the stateless SQL layer. It parses, plans and executes queries, and speaks the MySQL wire protocol, so existing MySQL clients, drivers, BI tools and application code connect to it unchanged.
- TiKV - the distributed transactional key-value store that actually holds the rows, organised into Raft-replicated regions.
- PD (Placement Driver) - the cluster's metadata store and scheduler. It tracks where data lives and rebalances it, and it also serves TiDB Dashboard.
This cloudimg image installs TiDB 8.5.7 (the v8.5 LTS line) from the official signed PingCAP mirror, SHA-256 verified during the build, and runs all three components on a single VM as systemd services, together with Prometheus and ng-monitoring so TiDB Dashboard's charts and diagnostics work out of the box. Backed by 24/7 cloudimg support.
What a single-node deployment does and does not give you
This is the smallest arrangement that is still a genuine TiDB cluster rather than a mock-storage stub, which makes it a faithful environment for development, evaluation, CI and staging, and a realistic way to learn the real component topology before scaling out.
It is also one PD member and one TiKV store, so every Raft group holds a single replica. Concretely:
- There is exactly one copy of your data.
- There is no automatic failover and no high availability.
- Losing the VM or its data disk means losing the database.
TiDB's production resilience comes from running three or more PD members and three or more TiKV stores across failure domains, so that Raft can retain a majority when one is lost. This image does not provide that and does not claim to. Treat backups as mandatory.
What is included:
- TiDB 8.5.7, TiKV and PD (all Apache-2.0), installed from the official signed PingCAP mirror and SHA-256 verified against the vendor's own signed manifest
- Prometheus and ng-monitoring, so TiDB Dashboard's Overview, Monitoring, Top SQL and Cluster Diagnostics pages work
- A per-VM
rootpassword generated at first boot - the image ships no bootstrapped cluster and therefore no account at all - A dedicated 64 GiB data disk for the PD and TiKV stores, kept off the OS disk
- Ubuntu 24.04 LTS, fully patched at capture, with unattended security upgrades enabled
Prerequisites
- An Azure subscription with permission to create virtual machines
- An SSH key pair
- A MySQL-compatible client on your workstation if you want to connect remotely (
mysql, MySQL Workbench, DBeaver, or any MySQL driver)
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for TiDB by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size (see Sizing - Standard_D4s_v5 is recommended); under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) only. Then Review + create -> Create.
First-boot initialisation generates your per-VM database password, bootstraps the cluster with that password already set, and starts all five services. Allow two to three minutes after the VM is running before the database accepts queries - TiDB creates its entire system-table catalogue on the very first bootstrap.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name tidb \
--image <marketplace-image-urn> \
--size Standard_D4s_v5 \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
A welcome banner prints the most useful commands.
Step 4 - Confirm the cluster is running
Five services make up the deployment. All five should report active.
systemctl is-active tidb-pd tidb-ngm tidb-prometheus tidb-tikv tidb
Expected output:
active
active
active
active
active
Check which ports are listening. Only the SQL port is bound on all interfaces; everything else is cluster-internal and bound to loopback.
ss -tlnp 2>/dev/null | grep -E '4000|2379|20160|20180|10080|12020|9090' | awk '{print $1, $4}' | sort -u

Ask PD directly whether the storage layer is genuinely serving. A TiKV store must be Up - this is the check that matters, because the SQL layer will accept connections even when storage is unavailable.
curl -s http://127.0.0.1:2379/pd/api/v1/stores | jq -r '.stores[] | "store \(.store.id) \(.store.address) \(.store.state_name)"'
Step 5 - Retrieve your per-VM database password
Upstream TiDB creates its root account with no password at all. This image never ships that default: it contains no bootstrapped cluster, and on first boot it generates a password unique to your VM and applies it as part of the very first cluster bootstrap, so an empty-password root never exists as a completed state.
The credentials file is readable only by root:
sudo ls -l /root/tidb-credentials.txt
sudo cat /root/tidb-credentials.txt

Store the password in your password manager. Because it is generated per VM, no two deployments of this image share a credential.
Step 6 - Connect over the MySQL protocol
TiDB speaks the MySQL wire protocol, so the ordinary mysql client works:
mysql -h 127.0.0.1 -P 4000 -uroot -p'<TIDB_ROOT_PASSWORD>' -e 'SELECT VERSION() AS server_version'
The version string identifies both the MySQL protocol level and the TiDB release:
+--------------------+
| server_version |
+--------------------+
| 8.0.11-TiDB-v8.5.7 |
+--------------------+
Step 7 - Run SQL
Create a database and table, insert rows and read them back. Every write here travels through the SQL layer into TiKV.
mysql -h 127.0.0.1 -P 4000 -uroot -p'<TIDB_ROOT_PASSWORD>' -t -e "
CREATE DATABASE IF NOT EXISTS quickstart;
DROP TABLE IF EXISTS quickstart.orders;
CREATE TABLE quickstart.orders (
id INT PRIMARY KEY AUTO_INCREMENT,
region VARCHAR(24),
amount DECIMAL(10,2)
);
INSERT INTO quickstart.orders (region, amount) VALUES
('emea', 120.50), ('apac', 340.00), ('amer', 75.25), ('emea', 210.75);
SELECT * FROM quickstart.orders;
SELECT region, COUNT(*) AS orders, ROUND(SUM(amount),2) AS revenue
FROM quickstart.orders GROUP BY region ORDER BY revenue DESC;"

Confirm the data is genuinely persisted rather than held in memory by restarting the whole stack and reading the same rows back:
sudo systemctl restart tidb-tikv tidb
for i in $(seq 1 60); do
mysql -h 127.0.0.1 -P 4000 -uroot -p'<TIDB_ROOT_PASSWORD>' -N -e 'SELECT 1' >/dev/null 2>&1 && break
sleep 2
done
mysql -h 127.0.0.1 -P 4000 -uroot -p'<TIDB_ROOT_PASSWORD>' -t -e 'SELECT COUNT(*) AS rows_after_restart FROM quickstart.orders'
The rows are read back from TiKV after the storage layer has been stopped and started, so they were genuinely on disk rather than held in memory.
Step 8 - Inspect the cluster
PD's view of the cluster, alongside a real aggregate query:
curl -s http://127.0.0.1:2379/pd/api/v1/stores | jq -r '.stores[] | "store \(.store.id) \(.store.address) \(.store.state_name) capacity=\(.status.capacity)"'

Step 9 - Open TiDB Dashboard over an SSH tunnel
TiDB Dashboard is a full web console for the cluster - instance topology, SQL statement analysis, slow queries, Top SQL and a key-space visualiser. It is served by PD, and on this image PD is bound to loopback only, because the PD client port also exposes unauthenticated cluster-administration APIs alongside the Dashboard. Reach it through an SSH tunnel rather than opening the port:
ssh -L 2379:127.0.0.1:2379 azureuser@<vm-public-ip>
With the tunnel open, browse to http://127.0.0.1:2379/dashboard. Sign in with username root and the password from Step 5 - the Dashboard authenticates against the TiDB SQL account, so rotating root secures the Dashboard too.

The Overview page shows queries per second, latency percentiles and CPU usage, drawn from the bundled Prometheus:

Cluster Info lists the real component instances and their versions:

SQL Statements aggregates the queries the cluster has actually executed, with latency and execution counts - the fastest way to find the statement worth optimising:

Grafana and Alertmanager are not included in this image; the Dashboard's own charts are backed by the bundled Prometheus, which is why the Monitor and Alert links on the Overview page are inactive.
Step 10 - Connect remotely
The Azure network security group created with this image opens SSH (22) only, and the TiDB SQL port is not reachable from outside the VM by default. Two options:
SSH tunnel (recommended) - no firewall change, and the database is never exposed to the network:
ssh -L 4000:127.0.0.1:4000 azureuser@<vm-public-ip>
mysql -h 127.0.0.1 -P 4000 -uroot -p
Open the port - if you need direct access from an application, add an inbound rule for TCP 4000 in your NSG, scoped to the source addresses that genuinely need it. Do not open it to the internet.
Sizing
TiDB is a distributed system, and the three components each size their memory as a percentage of total RAM by default - TiKV's block cache alone defaults to 45%, and the SQL layer's memory limit to 80% of the same RAM. This image sets every one of those ceilings explicitly and recomputes them from the machine's own RAM at each service start, so the same image behaves correctly across VM sizes.
Standard_D4s_v5 (4 vCPU / 16 GiB) is the recommended size. A D-series rather than a cheaper burstable B-series of the same size is a deliberate technical choice: TiKV runs continuous RocksDB background compaction, which is a sustained baseline CPU load. A burstable SKU drains its CPU credits under sustained load and then throttles to a low baseline, at which point compaction falls behind and write stalls appear - which looks like a database fault but is really a sizing fault. D-series SKUs have no credit model.
For context, PingCAP's own development and test guidance is well above this for each component separately (TiDB 8 cores / 16 GiB, TiKV 8 cores / 32 GiB, PD 4 cores / 8 GiB). Standard_D4s_v5 is an honest single-box development and evaluation size, not a claim of production capacity. Scale up for heavier workloads, and scale out to a multi-node cluster for anything needing fault tolerance.
Maintenance
The database and its data disk survive reboots; all five services start automatically.
systemctl status tidb --no-pager | head -5
Data lives on the dedicated data disk mounted at /var/lib/tidb:
df -h /var/lib/tidb | tail -1
Take backups. With a single replica there is no redundancy inside the cluster, so an Azure disk snapshot of the data disk, or a logical dump, is the only thing standing between you and data loss:
mysqldump -h 127.0.0.1 -P 4000 -uroot -p'<TIDB_ROOT_PASSWORD>' --databases quickstart > /tmp/quickstart-backup.sql
Ubuntu security updates are applied automatically by unattended-upgrades.
Support
This image is published and maintained by cloudimg with 24/7 support. For TiDB itself, see the PingCAP documentation. For image or deployment issues, contact cloudimg support.