Database Migration Service (DMS)
Moving a live production database to the cloud is scary. You cannot just turn the old system off for a weekend while you copy gigabytes of data, because real users are still writing to it. AWS Database Migration Service (DMS) solves this by copying your data into AWS and then continuously keeping the copy in sync with the source until you are ready to flip the switch. This page explains how DMS works, how it differs from the Schema Conversion Tool (SCT), and the one mistake that sinks most cross-engine migration projects.
What DMS actually does
AWS Database Migration Service (DMS) is a managed service that reads data out of a source database and writes it into a target database. The source can be on-premises (in your own data center), on another cloud, or already inside AWS. The target is usually an AWS database like Amazon RDS (Relational Database Service), Amazon Aurora, Amazon Redshift, Amazon DynamoDB, or Amazon S3 (Simple Storage Service).
DMS supports two kinds of moves:
- Homogeneous migration — same engine on both sides (Oracle to Oracle, MySQL to MySQL). This is the easy case; the data types and SQL line up.
- Heterogeneous migration — different engines (Oracle to PostgreSQL, SQL Server to Aurora MySQL). This is the hard case, and where SCT comes in.
The migration runs on a replication instance — an EC2 (Elastic Compute Cloud) server that DMS manages for you. It connects to the source, pulls the data through, transforms it on the fly if you ask it to, and loads it into the target.
Critical gotcha: DMS migrates data, not schema. It does NOT convert table definitions, stored procedures, triggers, functions, views, or your application’s SQL. For a same-engine move that is fine. For a cross-engine move (e.g. Oracle to Postgres), the schema and code conversion is a separate, often much larger job handled by the Schema Conversion Tool. Underestimating this is the number one reason heterogeneous migrations blow their timelines.
DMS vs SCT — who does what
| Concern | Handled by DMS | Handled by SCT |
|---|---|---|
| Row data (the actual records) | Yes | No |
| Table/column structure | No | Yes |
| Stored procedures, functions, triggers | No | Yes |
| Views, indexes, constraints | No | Yes |
| Application SQL embedded in code | No | Yes (assessment + conversion) |
| Ongoing change replication (CDC) | Yes | No |
SCT (AWS Schema Conversion Tool) is a free downloadable desktop application. For a heterogeneous move you run SCT first to convert the schema and produce an assessment report that lists exactly which objects convert automatically and which need manual rewriting. Then you run DMS to move the data.
Full load vs CDC
DMS migration tasks have two phases:
- Full load — a one-time bulk copy of all existing rows. Use this alone when you can afford downtime and the data is static during the cutover.
- Change Data Capture (CDC) — after the full load, DMS reads the source database’s transaction log and replays every insert, update, and delete onto the target in near real time. This keeps the target current while the source is still live, giving you near-zero-downtime cutover.
When to use full load + CDC: any production database that real users keep writing to. You do the bulk copy days in advance, let CDC catch up, verify the data matches, then point your application at the target during a tiny maintenance window.
When to use full load only: dev/test databases, or a read-only data set, where a clean copy with brief downtime is acceptable.
How to run a migration (Console)
- Open the AWS Management Console and go to Database Migration Service.
- Choose Replication instances then Create replication instance. Pick an instance class (start with
dms.t3.mediumfor small jobs), the VPC (Virtual Private Cloud) that can reach both source and target, and whether it is Multi-AZ for resilience. - Choose Endpoints then Create endpoint. Create one source endpoint (engine, host, port, credentials) and one target endpoint. Use Test connection on each before saving.
- Choose Database migration tasks then Create task. Select the replication instance, source and target endpoints, and a migration type: Migrate existing data (full load), Migrate existing data and replicate ongoing changes (full load + CDC), or Replicate data changes only (CDC only).
- Add table mappings (which schemas/tables to include) and start the task.
- Watch Table statistics on the task to confirm rows loaded and CDC is keeping up (look for low CDCLatencySource and CDCLatencyTarget in CloudWatch).
How to run a migration (CLI)
Create the replication instance:
aws dms create-replication-instance \
--replication-instance-identifier prod-migration \
--replication-instance-class dms.t3.medium \
--allocated-storage 50 \
--vpc-security-group-ids sg-0a1b2c3d \
--replication-subnet-group-identifier dms-subnet-group \
--multi-az
Output:
{
"ReplicationInstance": {
"ReplicationInstanceIdentifier": "prod-migration",
"ReplicationInstanceClass": "dms.t3.medium",
"ReplicationInstanceStatus": "creating",
"ReplicationInstanceArn": "arn:aws:dms:us-east-1:111122223333:rep:ABCD1234"
}
}
Create a migration task that does full load plus ongoing replication:
aws dms create-replication-task \
--replication-task-identifier oracle-to-aurora \
--source-endpoint-arn arn:aws:dms:us-east-1:111122223333:endpoint:SRCORACLE \
--target-endpoint-arn arn:aws:dms:us-east-1:111122223333:endpoint:TGTAURORA \
--replication-instance-arn arn:aws:dms:us-east-1:111122223333:rep:ABCD1234 \
--migration-type full-load-and-cdc \
--table-mappings file://table-mappings.json
Output:
{
"ReplicationTask": {
"ReplicationTaskIdentifier": "oracle-to-aurora",
"MigrationType": "full-load-and-cdc",
"Status": "creating"
}
}
A minimal table-mappings.json that includes every table in the HR schema:
{
"rules": [
{
"rule-type": "selection",
"rule-id": "1",
"rule-name": "include-hr",
"object-locator": { "schema-name": "HR", "table-name": "%" },
"rule-action": "include"
}
]
}
Then start it:
aws dms start-replication-task \
--replication-task-arn arn:aws:dms:us-east-1:111122223333:task:XYZ7890 \
--start-replication-task-type start-replication
Cost note
DMS bills mainly for the replication instance — you pay per hour while it runs, plus storage and any cross-region data transfer. A dms.t3.medium runs roughly a few US dollars a day. The big lever is runtime: full load only takes hours, but CDC keeps the instance running for the whole sync window (often days or weeks during validation), so the bill scales with how long you leave CDC on. Delete the replication instance the moment cutover is verified — a forgotten instance quietly costs money for months.
Best practices
- Run SCT first on any heterogeneous move and treat its assessment report as the real scope of work — budget time for the objects it flags as manual.
- Always use full load + CDC for live production databases; never plan a big-bang copy with extended downtime.
- Enable supplemental/transaction logging on the source before you start, or CDC will silently miss changes.
- Validate with DMS data validation (row counts and checksums) before cutover — never trust “the task says complete.”
- Size the replication instance for the full-load burst, then you can downsize for the lighter CDC phase.
- Use CloudWatch alarms on
CDCLatencyTargetso you know the target is keeping up before you cut over. - Delete the replication instance and endpoints once the migration is verified to stop ongoing charges.