Pick the path
| Source | Path | Downtime |
|---|---|---|
| RDS for MySQL | Create an Aurora read replica of the RDS instance, then promote | Minutes |
| EC2 / on-premises, large | XtraBackup → S3 → restore into Aurora, then binlog replication | Minutes |
| Any, small | mysqldump/MySQL Shell dump & load | Full duration |
| Any, heterogeneous needs | AWS DMS | Minutes |
Path A: from RDS for MySQL
aws rds create-db-cluster --db-cluster-identifier shop-aurora --engine aurora-mysql \
--replication-source-identifier arn:aws:rds:eu-west-1:111122223333:db:shop-rds \
--db-subnet-group-name db-subnets --vpc-security-group-ids sg-0abc
aws rds create-db-instance --db-instance-identifier shop-aurora-1 --db-cluster-identifier shop-aurora \
--engine aurora-mysql --db-instance-class db.r7g.xlarge
When ReplicaLag is near zero: stop writes, wait for 0, then promote:
aws rds promote-read-replica-db-cluster --db-cluster-identifier shop-aurora
Path B: from EC2 / on-premises
1. Physical backup to S3
xtrabackup --backup --user=backup --password=*** --stream=xbstream --target-dir=/tmp/xb \
| aws s3 cp - s3://shop-migr/backup/shop.xbstream
Aurora's "restore from S3" supports specific XtraBackup and MySQL versions and formats (full backups; check the docs for compression/streaming support). Many teams back up to local disk, then upload the files.
Record the binlog position / GTID from xtrabackup_binlog_info.
2. Restore into Aurora
Console: Restore from S3 (or aws rds restore-db-cluster-from-s3 with --source-engine mysql --source-engine-version ... --s3-bucket-name ... --s3-ingestion-role-arn ...). Then add an instance to the cluster.
3. Replicate the delta
On Aurora (network path to the source required):
CALL mysql.rds_set_external_source_with_auto_position('src-mysql.example.com', 3306, 'repl', '<password>', 0);
-- or with file/position from xtrabackup_binlog_info:
-- CALL mysql.rds_set_external_source('src-mysql.example.com', 3306, 'repl', '<password>', 'binlog.004211', 1547, 0);
CALL mysql.rds_start_replication;
SHOW REPLICA STATUS\G
Procedure names differ between Aurora versions (rds_set_external_master on older ones). Check your version's documentation. Set binlog retention on the source long enough to cover the restore time.
Validation
- Row counts/checksums on key tables (
pt-table-checksumwith the Aurora cluster as a replica). - Users and grants (not included in all paths). Recreate from
SHOW GRANTS. - Parameters: create a DB cluster parameter group with settings like
binlog_format(if Aurora must feed other consumers),time_zone,character_set_server.
Cut-over
- Stop writes on source;
super_read_only = ON. - Wait for lag 0 and equal GTID sets.
CALL mysql.rds_stop_replication; CALL mysql.rds_reset_external_source;- Point apps at the cluster endpoint; read-only traffic at the reader endpoint.
- Keep the source available read-only for rollback.
After go-live
- Failover test:
aws rds failover-db-cluster --db-cluster-identifier shop-aurora, and check app reconnect behaviour. - Consider RDS Proxy for apps with many short connections or slow failover handling.
- Backtrack (if enabled at creation) for quick undo of logical mistakes; Performance Insights for query load.
Tip
Use a DNS CNAME you control (e.g.
shop-db.internal) pointing at the cluster endpoint. Cut-over and any later move become a DNS change, not an app redeploy.
Checklist
- Path chosen by source type and size
- Backup/restore or replica lag measured in rehearsal
- Binlog retention covers the catch-up window
- Users, grants, parameters handled
- Apps on cluster/reader endpoints; failover tested