Checklist for Migrating from TiDB to Aurora MySQL
公開日 2026-08-13 · 更新日 2026-08-13 · 最終検証日 2026-08-13
結論
When migrating from TiDB to Aurora MySQL, do not assume "it's MySQL-compatible, so it will just work." Instead, verify seven things in your actual environment: ID generation (`AUTO_INCREMENT`'s non-sequential allocation and `AUTO_RANDOM`), primary key structure (clustered vs. non-clustered, `SHARD_ROW_ID_BITS`), TiDB-specific syntax and system variables, transaction behavior, statistics and index selection, character set and collation, and capacity (TiKV and InnoDB require different amounts). Since behavior changes across TiDB versions, this assumes you verify against your own environment's version rather than this article.
この文書の適用条件
| 対象製品 | TiDB (source) → Aurora MySQL (target) |
|---|---|
| 確認バージョン | TiDB behavior varies significantly by version, so always run `SELECT TIDB_VERSION();` to check your environment's version before verifying each item. Assumes the target is Aurora MySQL 3.x (MySQL 8.0-compatible) |
| 適用環境 | TiDB (self-hosted / managed) → Amazon Aurora (AWS) |
| 必要権限 | Investigation requires read access to `information_schema` and `SELECT` on the target schema. Running the migration requires read access on the dump source and write access on the target |
| 実行影響 | No impact from the investigation SQL. The initial load and CDC setup put load on both the source and target |
| 再起動 | Not required for investigation. Cutover downtime depends on the method chosen |
| 最終検証日 | 2026-08-13 |
そのまま実行できるコマンド
- 対象
- TiDB (all versions)
- 権限
- Connection privilege
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: TiDB(バージョンにより出力が異なる)
-- 権限: 接続権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
-- 1) TiDB のバージョン(VERSION() はMySQL互換の文字列、TIDB_VERSION() はTiDB固有の詳細)
SELECT VERSION() AS mysql_compat_version;
SELECT TIDB_VERSION() AS tidb_version;
-- 2) トランザクションモードと分離レベル
SHOW GLOBAL VARIABLES WHERE Variable_name IN (
'tidb_txn_mode',
'transaction_isolation',
'tidb_constraint_check_in_place',
'tidb_enable_clustered_index'
);
-- 3) 新しい照合順序フレームワークが有効かどうか
-- (無効な環境では utf8mb4_general_ci の比較挙動がMySQLと異なる)
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM mysql.tidb
WHERE VARIABLE_NAME = 'new_collation_enabled';The version obtained here is the premise for every decision that follows. Since TiDB's defaults and supported features change across versions, prefer your own environment's output whenever it conflicts with this article. `mysql.tidb` or `tidb_enable_clustered_index` may not exist in some versions (if you get an error, you can conclude that version simply lacks the feature).
- 対象
- TiDB (all versions)
- 権限
- Metadata read privilege on the target schema
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: TiDB(全バージョン)
-- 権限: 対象スキーマのメタデータ参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
-- 1) 定義そのものを出力し、AUTO_RANDOM / SHARD_ROW_ID_BITS /
-- CLUSTERED・NONCLUSTERED / PRE_SPLIT_REGIONS の有無を目視で確認する
SHOW CREATE TABLE SampleDB.sample_table;
-- 2) 主キーの構造を一覧で確認する(TIDB_PK_TYPE はTiDB独自列。
-- 存在しない版ではエラーになるので、その場合は 1) を全テーブル分実行する)
SELECT TABLE_SCHEMA, TABLE_NAME, TIDB_PK_TYPE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'metrics_schema', 'sys')
ORDER BY TABLE_SCHEMA, TABLE_NAME;
-- 3) 主キーの無いテーブル(移行後のCDCで問題になる)
SELECT t.TABLE_SCHEMA, t.TABLE_NAME
FROM information_schema.TABLES t
LEFT JOIN information_schema.KEY_COLUMN_USAGE k
ON k.TABLE_SCHEMA = t.TABLE_SCHEMA
AND k.TABLE_NAME = t.TABLE_NAME
AND k.CONSTRAINT_NAME = 'PRIMARY'
WHERE t.TABLE_TYPE = 'BASE TABLE'
AND t.TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'metrics_schema', 'sys')
AND k.COLUMN_NAME IS NULL
ORDER BY t.TABLE_SCHEMA, t.TABLE_NAME;`AUTO_RANDOM` is specific to TiDB and has no MySQL equivalent. A column using it needs to be replaced with a different design on the Aurora MySQL side (a sequential `BIGINT`, application-side ID generation, a UUID scheme, etc.) — consider both value compatibility and digit count. `SHARD_ROW_ID_BITS` and `PRE_SPLIT_REGIONS` are settings for TiKV's distributed placement and have no equivalent concept on Aurora (this doesn't mean you can simply ignore them — consider what happens after migration to the access pattern that needed that setting).
- 対象
- TiDB (all versions)
- 権限
- Metadata read privilege on the target schema
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: TiDB(全バージョン)
-- 権限: 対象スキーマのメタデータ参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
-- 1) 外部キー定義の有無(定義があっても実際に強制されているかは版に依存する)
SELECT CONSTRAINT_SCHEMA, TABLE_NAME, CONSTRAINT_NAME,
REFERENCED_TABLE_NAME, UPDATE_RULE, DELETE_RULE
FROM information_schema.REFERENTIAL_CONSTRAINTS
ORDER BY CONSTRAINT_SCHEMA, TABLE_NAME;
-- 2) 生成列(GENERATED COLUMN)
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, EXTRA, GENERATION_EXPRESSION
FROM information_schema.COLUMNS
WHERE GENERATION_EXPRESSION IS NOT NULL
AND GENERATION_EXPRESSION <> ''
ORDER BY TABLE_SCHEMA, TABLE_NAME;
-- 3) パーティション定義
SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, PARTITION_METHOD, PARTITION_EXPRESSION
FROM information_schema.PARTITIONS
WHERE PARTITION_NAME IS NOT NULL
ORDER BY TABLE_SCHEMA, TABLE_NAME, PARTITION_ORDINAL_POSITION;TiDB has, for a long time, accepted foreign key syntax without actually enforcing the constraint. Since whether it's enforced depends on the version, check the real behavior in your environment by trying a violating INSERT rather than just checking whether a definition exists. If it was not enforced before, data inserts that previously succeeded may start failing once foreign keys are enforced on the Aurora MySQL side.
- 対象
- TiDB (all versions)
- 権限
- Read access to `information_schema`
- 変更作業
- None (read-only)
- Production実行
- Possible
-- 対象: TiDB(全バージョン)
-- 権限: information_schema の参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
TABLE_SCHEMA,
TABLE_NAME,
TABLE_ROWS AS estimated_rows,
ROUND(DATA_LENGTH / 1024 / 1024 / 1024, 2) AS data_gb,
ROUND(INDEX_LENGTH / 1024 / 1024 / 1024, 2) AS index_gb,
TABLE_COLLATION
FROM information_schema.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'metrics_schema', 'sys')
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;TiDB's `TABLE_ROWS` and `DATA_LENGTH` are estimates based on statistics. Since TiKV keeps multiple replicas and also compresses data, you cannot use this value as-is for Aurora's (InnoDB's) required storage. Estimate the target capacity from the actual ratio measured by loading representative tables.
- 対象
- TiDB (Dumpling)
- 権限
- `SELECT` on the dump target schema (TiDB side)
- 変更作業
- None (source is read-only), but it adds read load
- Production実行
- Carry out during a window that can tolerate the load
# 対象: TiDB(Dumpling によるダンプ)
# 権限: ダンプ対象スキーマへの SELECT(TiDB側)
# 変更作業: なし(移行元は参照のみ)。ただし読み取り負荷がかかる
# Production 実行: 負荷を許容できる時間帯で実施すること
# まず1テーブルだけダンプして所要時間と出力サイズを実測する
tiup dumpling \
--host 192.0.2.10 \
--port 4000 \
--user sample_user \
--filetype sql \
--threads 8 \
--rows 200000 \
--filter 'SampleDB.sample_table' \
--output /var/tmp/dump-sample
# 出力サイズと所要時間を確認する(この実測値だけが計画の根拠になる)
du -sh /var/tmp/dump-sampleMeasure with a few tables first, then extrapolate to the whole. Specifying `--rows` splits a table for parallel output. Raising `--threads` increases load on the source, so start low while in production. Option names can change between Dumpling versions, so check with `tiup dumpling --help`.
- 対象
- TiCDC (TiDB side) or AWS DMS
- 権限
- Operational privileges on TiCDC, or DMS IAM privileges and endpoint credentials
- 変更作業
- Yes (configures change data delivery; affects both source and target)
- Production実行
- A configuration change on the production source. Pre-verification and a rollback procedure are mandatory
# 対象: TiCDC(TiDB側)または AWS DMS
# 権限: TiCDC の操作権限、または DMS の IAM 権限とエンドポイント資格情報
# 変更作業: あり(変更データ配信の構成)
# Production 実行: 本番ソースへの設定変更。事前検証と切り戻し手順を用意してから実施
# TiCDC で MySQL 互換のシンク(= Aurora MySQL)へ変更を流す例。
# CLI のオプション名はTiDB/TiCDCのバージョンで変わる(--pd と --server など)ため、
# 必ず自環境のバージョンのドキュメントで確認すること。
tiup ctl cdc changefeed create \
--server "http://192.0.2.10:8300" \
--changefeed-id "example-changefeed" \
--sink-uri "mysql://sample_user@example-rds-endpoint:3306/"
# 作成後は状態と遅延を確認する
tiup ctl cdc changefeed list --server "http://192.0.2.10:8300"The TiCDC CLI's option names have changed across versions (e.g., `--pd` to `--server`). Don't use the exact form shown here — match it to your own environment's version documentation. If using AWS DMS against a source TiDB, check with the actual DMS version you'll use whether TiDB is supported as a source and which mode (full-load only / including CDC) is available (this article does not state this definitively). Don't write the password directly on the command line — use an environment variable or a config file.
結果の読み方
| 列 | 意味 | 確認するポイント |
|---|---|---|
| tidb_version | TiDB's actual version | The premise for every compatibility decision. Prefer your own environment's version over this article |
| tidb_txn_mode | Transaction mode (optimistic / pessimistic) | If optimistic, the app may be written assuming a conflict error is returned at commit time |
| new_collation_enabled | Whether the new collation framework is enabled | If disabled, comparison behavior for utf8mb4-family collations differs from MySQL. Duplicate detection may change after migration |
| TIDB_PK_TYPE | Whether the primary key is clustered | Performance characteristics assumed under clustering are not guaranteed to be reproduced on Aurora |
| estimated_rows | Estimated row count based on statistics | Not an exact count. Cross-check against a verification `COUNT(*)` |
| data_gb / index_gb | Data and index size as reported by TiDB | Includes TiKV replication and compression, so it can't be used as-is for Aurora's required capacity |
| REFERENCED_TABLE_NAME | What a foreign key references | Check whether it is actually enforced by testing, not just whether a definition exists |
| GENERATION_EXPRESSION | Expression for a generated column | Check individually whether function support matches on the target |
こういう状況で使います
- SQL that worked on TiDB produces an error in the Aurora MySQL test environment
- Continuity of ID generation changes after migration, conflicting with application assumptions
- The same index exists, but only after migration does the execution plan change and slow down
- Data that violates a foreign key already exists and cannot be loaded into the target
- The target's storage estimate diverges significantly from the source's reported value
- String comparison or sorting results changed before and after migration
考えられる原因(可能性の高い順)
01
`AUTO_INCREMENT` allocation works differently
Because TiDB allocates ID ranges in bulk to each node, IDs can be non-sequential. An application that assumes "higher ID = later insertion order" needs re-review regardless of which side it runs on. Since the exact behavior depends on version and configuration, measure sequentiality in your own environment.
02
MySQL has no equivalent of `AUTO_RANDOM`
This is a TiDB-specific feature for avoiding hotspots. When migrating to Aurora MySQL, the value-generation scheme itself needs to be redesigned. Also check whether existing ID values can be carried over as-is.
03
The clustered-primary-key assumption differs
InnoDB is clustered by the primary key by default, while TiDB lets you choose clustered or non-clustered. A non-clustered table's per-access-pattern performance characteristics change after migration.
04
Transaction behavior differs
Optimistic transactions detect conflicts at commit time, while pessimistic transactions take locks at execution time. Which one was in use changes how lock waits and errors manifest after migration.
05
TiDB-specific syntax, system variables, or hints are in use
System variables starting with `TIDB_`, TiDB-specific optimizer hints, and `ADMIN`-family administrative commands don't work on MySQL. Full-text search the application and batch SQL to find them.
06
The statistics and index selection mechanism differs
Since the optimizer is a different implementation, the execution plan chosen can differ even with the same index configuration. Treat "the same SQL is now slow" after migration as expected, and plan to re-verify execution plans for representative queries on the target.
07
The storage structure differs
TiKV keeps replicas and also compresses data. Since the assumptions differ from InnoDB, you cannot mechanically convert the source's usage into the target's required capacity.
確認手順
- 1
Retrieve TiDB's version and key settings
参照のみCheck `TIDB_VERSION()`, `tidb_txn_mode`, and the state of the collation framework. Every subsequent decision is premised on this result.
- 2
Save `SHOW CREATE TABLE` for every table
参照のみSome TiDB-specific attributes appear only in the definition statement. Save all of them and search for `AUTO_RANDOM` / `SHARD_ROW_ID_BITS` / `NONCLUSTERED`.
- 3
Full-text search the application SQL for TiDB-specific elements
参照のみSearch for `TIDB_`, custom hints, and `ADMIN` commands. These aren't visible from the DB side, so they need to be found in the code.
- 4
Test in a verification environment whether foreign keys are actually enforced
中Run a violating INSERT and check whether it errors. This cannot be determined from the definition alone.
- 5
Test-load a representative table on the target and measure the capacity ratio
中This measured value alone is the basis for estimating the target's storage.
- 6
Run representative queries on the target and compare execution plans and timing
中There is no guarantee of the same performance as the source. Include time in the plan to handle queries that show a difference individually.
対応方法
すぐに実施できる低リスクの対応
Pin down the version and list the differences
参照のみJudge based on "this specific version of TiDB," not "TiDB" in general. The list of differences becomes the backbone of the migration plan.
Separate what will and will not be migrated
参照のみIf temporary tables or large analytical tables can be excluded from migration, the burden of the initial load drops significantly.
事前検討が必要な変更
Replace the design of `AUTO_RANDOM` columns
高Decide on the target-side ID-generation scheme (sequential, application-generated, UUID-based) and check whether existing values can be carried over and whether the digit count fits application assumptions. Involves application-side changes.
Provision keys for tables with no primary key
高When synchronizing differences via CDC, a table with no primary key causes apply errors. Define a key before migration.
Re-verify execution plans for representative queries on the target
中Reserve a verification period in the plan on the assumption that indexes will need to be added or changed on the target.
Standardize the character set and collation to the target's baseline
中Collation differences change comparison results. See the related article for utf8mb4 migration checks.
再起動・サービス影響を伴う変更
Carry out the initial load
高Dump with Dumpling or similar and load it into the target. Always estimate the duration from a sample measurement.
Set up change data capture (TiCDC / DMS)
高This is a configuration addition on the production source. Decide how lag will be monitored and the rollback procedure before carrying this out.
専門家のレビューが必要な作業
Carry out the cutover
専門家レビュー必須Decide the order and ownership of stopping writes, confirming the difference has caught up, verifying consistency, switching the connection target, and the rollback decision, before carrying it out. This is an area driven by pre-agreed procedure and human judgment, not automation.
!注意事項
- TiDB's behavior varies by version. Whenever this article's description conflicts with your own environment's output, always prefer your environment's output.
- "MySQL-compatible" does not mean "identical." Syntax being accepted is a different matter from producing the same result and the same performance.
- Do not convert the source's `DATA_LENGTH` directly into Aurora's required storage. TiKV's value assumes replicas and compression.
- A foreign key may not be enforced even if it is defined. If it becomes enforced on the target, existing data loading or existing processing can start failing.
- This article does not give a duration for the migration. Since it depends on table composition, data volume, network, and parallelism, always estimate it from a sample measurement.
- Cutover is a hard-to-reverse operation. Define the point of no return beforehand and decide who makes the call before carrying it out.
バージョン・環境による違い
これで解決しない場合に確認すること
Check the application's driver and timeout settings
Changing the connection target can change reconnection and timeout behavior.
Decide where analytical workloads go
If analytical queries were co-located on TiDB, Aurora alone may not provide the same performance characteristics. Consider a read replica or a separate platform.
Re-measure batch processing parallelism and duration
Since the storage structure changes, the same degree of parallelism is not guaranteed to be optimal.
Rebuild operational procedures (backup, monitoring, privilege management) for the target
TiDB-specific procedures cannot be used as-is. Include creating operational procedures in the migration plan.
Check the conditions and procedure for rolling back
Document, before the cutover, how far back you can roll back and what gets discarded if you do.
この文書の根拠と限界
一般的な技術説明
Based on the publicly documented differences between TiDB and MySQL (Aurora MySQL) and general verification practices for cross-engine database migration. Since TiDB's behavior varies significantly by version, this article shows what to check rather than asserting any specific behavior. It does not include any specific customer's migration case or actual duration figures.
よくある質問
TiDB is MySQL-compatible, so can it be migrated as-is?
Not necessarily. What's compatible is the connection protocol and most SQL syntax; ID generation behavior, primary key structure, transaction behavior, statistics and index selection, and storage assumptions all differ. Treat syntax being accepted as separate from getting the same result and the same performance, and verify each item individually.
What should be done about columns using AUTO_RANDOM?
Since MySQL has no equivalent feature, the ID-generation scheme itself needs to be redesigned. Decide whether to use sequential IDs, application-side generation, or a UUID scheme, and check whether existing ID values can be carried over as-is and whether the digit count fits application assumptions.
How much storage is needed on the target?
It cannot be determined from the source's reported value. Since TiKV keeps replicas and also compresses data, its assumptions differ from InnoDB's. Actually load representative tables into the target and estimate the total from that ratio.
Can this be run in production?
All the investigation SQL is read-only and can be run on a production TiDB. A Dumpling dump adds read load and needs a scheduled window; configuring TiCDC or DMS is a configuration change on the production source. Carry out the cutover following a pre-agreed procedure.
What happens to foreign keys?
On TiDB, a foreign key may be defined but not actually enforced. Since whether it's enforced depends on the version, insert violating data to check the actual behavior. If it was not enforced, existing processing may start failing once foreign keys become active on the target.
How should the results be interpreted?
Classify each checklist item into one of three categories: "no difference," "needs an application change," or "needs a design change." If there is even one item requiring a design change, the migration becomes a project that includes application modification, not just a data move. Build the schedule on that premise.
この文書がカバーする質問
- How to check index differences between MySQL-compatible databases
- Want to know why AUTO_INCREMENT is not sequential in TiDB
- Data volume estimation when migrating from TiDB to RDS
- Does a TiDB foreign key behave the same as in MySQL
リスク表示の意味
- 参照のみデータと設定を変更しません。
- 低影響は限定的ですが、権限と負荷の確認が必要です。
- 中性能・ロック・コストに影響する可能性があります。
- 高障害・データ損失・復旧作業が発生する可能性があります。
- 専門家レビュー必須本番適用前に別途レビューが必須です。
GIIPの対応範囲
The migration decision itself can proceed just by filling out this article's checklist in your own environment. What's burdensome is the period after cutover spent continuously catching "problems that didn't show up on the source." For a period after cutover, GIIP tracks the execution time, execution plan, and error rate of representative queries alongside their pre-migration values, isolating only the ones that show degradation as something to act on. The migration work itself is decided by a person, while the ongoing comparison and initial investigation afterward are handled by an AI agent.
執筆・技術検証
GIIP プロダクション運用チーム
大規模Webサービス、SQL Server、Oracle、AWS、Azureの設計・移行・運用に約30年従事。x12largeクラスのAWS RDS for SQL Server環境12セット、約12万テーブルのOracle環境、約3TBのTiDBからAurora MySQLへの移行を経験。現在も複数のクラウドデータベースと約30のWebサービスを、AIエージェントと人間の専門家が継続的に監視・運用しています。
How to Plan a 3TB-Scale Database Migration
A 3TB-class migration plan is built in this order: measure actual size, choose a cutover method, measure duration with a trial run, and design verification and rollback. This is a procedure for setting the schedule from measured values rather than rule-of-thumb figures.
aurora-mysqlWhat to Check When Migrating from utf8mb3 to utf8mb4 in Aurora MySQL
The first thing that breaks when converting to utf8mb4 is index key length. This organizes the SQL for finding targets, how to choose a collation, the impact of conversion, and where the settings live.
aurora-mysqlWhy AWS DMS Reports Error 1032 and How to Investigate It
Error 1032 in DMS CDC means the corresponding row doesn't exist on the target. This organizes how to read the control tables, how to check for primary key mismatches, and the available task-setting options.
awsThe Difference Between One Large RDS Instance and Several Smaller Instances
A document organizing the technical differences between "one large instance" and "several smaller instances" for RDS sizing, and the CloudWatch metrics you should measure before deciding.
関連サービス
Request a migration assessment from TiDB
同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。
Request a migration assessment from TiDB