Try TiDB Cloud
Run your real workload patterns against a single SQL endpoint and turn "it should work" into proof. Real results without shard boundaries, and a before/after ops comparison you can take to leadership.
Jump to a Section
You built on Amazon Aurora MySQL because it promised scale and managed convenience. Now you are hitting walls. Write throughput plateaus even after you add read replicas. You are eyeing application-side sharding, but that means rewriting routing logic, managing cross-shard transactions, and multiplying your operational surface. Every new tenant or workload threatens to push you over the edge.
There is a clearer path forward. TiDB is a distributed SQL database that gives you MySQL horizontal scaling without the architectural gymnastics. Write throughput scales as you add nodes. You keep MySQL compatibility and avoid vendor lock-in. And migration happens with minimal application changes or rewrites: you point your connection strings at a new endpoint. This playbook shows you how to execute an Amazon Aurora MySQL migration that unlocks growth instead of multiplying complexity.
Storage leads own the database platform: capacity planning, cost, the managed-versus-control trade-off, and the long-term shape of your horizontal scaling plan. When Amazon Aurora's architecture constrains growth, they are the ones tasked with finding Aurora alternatives that preserve uptime while enabling the next phase of scale.
SREs live with the consequences. They own uptime SLAs, incident response, and the runbooks that keep services healthy. For them, Amazon Aurora's single-writer ceiling and proprietary features create operational friction that compounds with every new cluster.
If any of these sound familiar, you are the audience:
What both groups need from an Amazon Aurora migration:
Teams do not migrate away from Amazon Aurora on a whim. The decision comes after hitting specific ceilings that force uncomfortable architectural choices. Here is what the breaking point looks like.
Amazon Aurora separates compute from storage, which is excellent for read scaling: you add read replicas easily and they share the same storage layer. But writes flow through a single writer instance. According to AWS's own figures, Amazon Aurora MySQL processes up to roughly 200,000 writes per second on its largest supported instance class, and its original published benchmark measured about 101,000 write requests per second. Those numbers are ceilings, not floors: they represent the top of what a single writer can do, and once you reach them there is no larger instance to buy. Your real-world ceiling is typically lower, since production workloads rarely match a tuned sysbench benchmark.
As you approach the ceiling, the symptoms are consistent:
At this point your options narrow. You can shard at the application layer, which means rewriting core logic and accepting cross-shard transaction complexity. Or you can move to a distributed SQL architecture that scales writes horizontally with minimal application changes or rewrites.
Amazon Aurora's proprietary features are convenient early and constraining later. Capabilities like Backtrack and Aurora Serverless do not map cleanly to other MySQL-compatible databases, which locks you into AWS in subtle ways:
Teams usually realize portability matters at an inconvenient moment: a new region where Amazon Aurora options are limited, a compliance requirement for data residency, or an acquisition running on different infrastructure. By then the Amazon Aurora-specific dependencies are already spread through the codebase.
See how a distributed SQL database removes the single-writer ceiling and scales writes with node count.
TiDB addresses Amazon Aurora MySQL limitations with a different architecture. Instead of a single-writer model, TiDB distributes data and writes across many nodes. You get MySQL horizontal scaling for reads and writes, keep MySQL compatibility for a straightforward migration, and preserve portability across clouds and on-premises.
TiDB is MySQL compatible at the protocol and syntax level, so existing applications, ORMs, and tools work with minimal modification. Unlike Amazon Aurora's single writer, TiDB distributes writes across the cluster. As you add storage nodes, write capacity grows.
The architecture has three parts:
-- Connect with a standard MySQL client
mysql -h tidb-cluster.example.com -P 4000 -u root
-- Run standard MySQL queries
SELECT COUNT(*) FROM orders WHERE created_at > NOW() - INTERVAL 1 DAY;This distribution removes the need for application-level sharding. The database grows by adding nodes, not by fragmenting your data model or your routing logic. Because writes spread across TiKV nodes rather than funneling through one writer, write capacity scales roughly linearly with node count, so you raise the ceiling by adding hardware instead of hitting a single-instance wall. Exact throughput depends on your schema, workload, and hardware, so benchmark against your own workload rather than a headline number.
MySQL high availability in TiDB is automatic and does not depend on proprietary services. Data replicates using the Raft consensus algorithm across multiple nodes, typically three replicas. If a node fails, the cluster elects a new leader for the affected Regions within seconds, with no manual failover orchestration.
With TiDB you manage one logical database instead of a fleet of Aurora clusters. Backups, monitoring, access control, and capacity planning operate at the cluster level, not per shard.
When you hit Aurora's write ceiling, one path leads to sharding complexity and the other to horizontal scale without architectural surgery.
The conventional answer to Aurora's write ceiling is more Aurora clusters plus application-level sharding. It is well documented and painful.
# Example: app-side routing logic (illustrative)
def get_shard_for_user(user_id):
shard_number = hash(user_id) % TOTAL_SHARDS
return SHARD_CONNECTIONS[shard_number]
# Cross-shard reads become an application problem
def get_recent_orders_all_users(cutoff):
results = []
for shard in SHARD_CONNECTIONS:
partial = shard.query(
"SELECT * FROM orders WHERE created_at > ?", cutoff)
results.extend(partial)
return sorted(results, key=lambda x: x.created_at)TiDB removes the sharding logic by distributing writes at the storage layer. Your application sees one logical database. The cluster handles distribution, replication, and rebalancing.
-- Same query, distribution handled transparently
INSERT INTO orders (user_id, product_id, amount)
VALUES (12345, 67890, 99.99);
-- The application does not know which node stores this row.| Capability | Aurora Sharding | TiDB |
|---|---|---|
| Write throughput | Ceiling per cluster; grows only by adding shards | Grows with node count |
| Application changes | Extensive: routing, cross-shard logic, transaction compromises | Minimal: same MySQL protocol and SQL |
| Operational complexity | Multiplies with shard count | Constant: one cluster |
| Cross-partition queries | Application responsibility (scatter-gather) | Native SQL joins and aggregations |
| Rebalancing | Manual re-sharding | Automatic (PD) |
| ACID guarantees | Per-shard; cross-shard is eventual | Full ACID across the cluster |
Migrating from Aurora to TiDB follows a structured path that minimizes risk and keeps service continuity. Here is the flight plan.
Inventory your Aurora usage to find dependencies and compatibility concerns: Aurora-specific features, storage-engine variations, and custom extensions.
-- Inventory Aurora-specific variables
SHOW VARIABLES LIKE 'aurora%';
-- Identify the largest tables for migration planning
SELECT TABLE_SCHEMA, TABLE_NAME,
ROUND((DATA_LENGTH + INDEX_LENGTH)/1024/1024/1024, 2) AS size_gb,
TABLE_ROWS
FROM information_schema.TABLES
WHERE TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema')
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC
LIMIT 20;Document the Aurora-specific features your application relies on. Most have TiDB equivalents or can be refactored, but knowing them up front prevents cutover surprises.
Normalize dialect differences and validate the schema on a TiDB staging cluster.
# Export the Aurora schema (illustrative)
mysqldump --no-data --skip-triggers --triggers \
-h aurora-cluster.amazonaws.com -u admin -p mydatabase > schema.sql
# Import on a TiDB staging cluster (illustrative)
mysql -h tidb-staging.example.com -P 4000 -u root mydatabase < schema.sqlRun your application's integration tests against staging. This confirms queries behave correctly and surfaces any differences early.
Choose your tool by downtime tolerance and data volume. For minimal downtime, use TiDB Data Migration (DM) or AWS Database Migration Service to replicate continuously from Aurora to TiDB.
# TiDB Data Migration task (illustrative)
name: aurora-to-tidb
task-mode: all # full load + incremental
target-database:
host: "tidb-prod.example.com"
port: 4000
mysql-instances:
- source-id: "aurora-source"# Start replication and monitor lag
tiup dmctl --master-addr <addr>:8261 start-task dm-task.yaml
tiup dmctl --master-addr <addr>:8261 query-status aurora-to-tidbExecute the switchover when replication lag is minimal and validation passes. Two strategies:
Dual-write (lower risk, requires application changes): write to TiDB as the new source of truth and to Aurora as a rollback safety net during a validation window, then remove the Aurora writes.
Direct switchover (faster, brief write freeze):
-- Validation pattern: compare counts across critical tables
-- Run on both Aurora and TiDB immediately before cutover
SELECT 'orders' AS table_name, COUNT(*) AS row_count,
MAX(created_at) AS latest FROM orders
UNION ALL
SELECT 'customers' AS table_name, COUNT(*) AS row_count,
MAX(updated_at) AS latest FROM customers;After cutover, tune for your workload: set placement policies for hot data, configure resource control if needed, and scale out to meet your throughput targets.
-- Find the slowest statements post-migration
SELECT digest_text,
SUM(sum_latency)/SUM(exec_count)/1000000 AS avg_ms,
MAX(max_latency)/1000000 AS max_ms,
SUM(exec_count) AS exec_count
FROM information_schema.cluster_statements_summary
GROUP BY digest, digest_text
ORDER BY avg_ms DESC LIMIT 20;Map your Aurora usage into a phased migration sequence with clear validation gates and a clean rollback path.
After migration, build operational patterns that use TiDB's architecture instead of inheriting Aurora's complexity.
Unlike a single-writer ceiling, TiDB capacity planning is predictable: monitor write-throughput trends and add nodes before you hit constraints. A good rule is to scale out when sustained writes approach roughly 80% of current cluster capacity.
TiDB provides built-in dashboards and Prometheus metrics for cluster-wide observability. Key metrics: query latency (p95, p99), write throughput, Region distribution balance, storage utilization per node, and replication lag.
Use TiDB's Backup & Restore (BR) for cluster-wide backups. One schedule covers the whole distributed database instead of per-shard choreography.
# Illustrative BR full backup
tiup br backup full \
--pd "${PD_IP}:2379" \
--storage "s3://backups/tidb/$(date +%Y%m%d)"Real teams have moved off Aurora's single-writer constraints onto TiDB and kept performance predictable as workloads grew.
Plaid migrated from Amazon Aurora MySQL to TiDB to escape the reliability, maintenance, and scaling limits of a single-writer architecture. The scale of the project is the proof point: a six-person team moved 234 databases across roughly 100 services from Aurora to self-hosted TiDB over about two and a half years, using a phased approach that started with non-critical services and frontloaded the riskiest Tier 0 workloads.
The operational results are the part worth showing leadership:
Plaid evaluated alternatives including Google Spanner and chose TiDB for its MySQL compatibility, horizontal scalability, and distributed transactions, a direct match for teams looking for an Amazon Aurora alternative that does not require rewriting the application layer.
If you are ready to validate an exit plan with real workload data, these steps get you to a go/no-go decision quickly.
Run your real workload patterns against a single SQL endpoint and turn "it should work" into proof. Real results without shard boundaries, and a before/after ops comparison you can take to leadership.
A working session that maps your Aurora usage into a phased migration sequence with clear validation gates and a clean rollback path.
Near-zero-downtime migration is the standard approach. Using TiDB Data Migration or AWS DMS, you perform a full load followed by continuous replication, then cut over during a short write freeze once replication lag reaches zero and validation passes.