How a B2B SaaS Team Migrated 8 TB from Self-Managed MySQL to Aurora with Zero Downtime

A 120-engineer SaaS company moved 8 TB of MySQL data to Aurora MySQL with no service interruption, using DMS continuous replication, schema versioning, and a traffic-shifting cutover that took under 4 minutes.

Data & Storage · advanced · 12 min read · 2688 words · By Sandip Das · Published

What this covers

  1. The Situation
  2. The Problem
  3. Constraints
  4. Options Considered
  5. The Solution
  6. Implementation
  7. Results
  8. What Went Wrong Along the Way
  9. Lessons Learned
  10. Apply It Yourself

Key numbers

MetricBeforeAfter
P99 API latency during peak payroll window4,200 ms310 ms
Database I/O utilisation at peak97%41%
Unplanned database downtime (trailing 6 months)94 minutes0 minutes
On-call DB alerts per week16.11.4
Database tier infrastructure cost per month$28,000$19,400

Key components

  • AWS Database Migration Service (DMS) CDC — Continuously replicated changes from the MySQL binary log to Aurora, keeping the target within seconds of the source and enabling a traffic-flip cutover rather than a data-move cutover.
  • RDS Proxy — Pooled up to 3,200 application connections into a manageable Aurora connection count and served as the single endpoint that the cutover flag redirected, making the switch transparent to the application.
  • AWS Parameter Store feature flag — Stored the cutover decision as a runtime configuration value so the endpoint switch could be executed and rolled back in seconds without a code deployment.
  • Flyway schema manager — Applied DDL migrations to Aurora independently of the DMS replication task, keeping schemas synchronised throughout the CDC phase and eliminating schema drift as a cutover risk.
  • CloudWatch CDC lag alarm with Lambda auto-restart — Detected DMS task failures caused by transient network issues and automatically restarted the CDC task, removing a manual intervention requirement from the cutover runbook.
  • Aurora MySQL 3.x multi-AZ cluster — Provided the target database with sub-second read replica lag, automatic storage scaling, continuous S3 backups, and zero-downtime failover — capabilities unavailable on the self-managed colo hardware.

The Situation

The company is a 120-engineer B2B SaaS platform serving mid-market HR and payroll customers across North America and Europe. Their core product — payroll processing, benefits administration, and compliance reporting — runs on a monolithic Rails application backed by a self-managed MySQL 5.7 cluster hosted on three bare-metal servers in a co-location facility in Northern Virginia. The database tier holds approximately 8 TB of data spread across 340 tables, with the largest tables being payroll_runs (1.1 TB), audit_events (900 GB), and employee_documents (1.4 TB, mostly BLOBs).

The engineering team is split into six product squads and a platform team of twelve. The platform team owns infrastructure, reliability, and the migration project. They run Terraform for infrastructure-as-code, deploy via GitHub Actions to AWS, and use Datadog for APM and alerting. The application tier already lives in AWS (us-east-1), so the database sitting in a colo was already a cross-environment latency problem.

The rest of this case study — the trade-offs, the scaling numbers and the build prompt — is available to LearnXops members. Create an account or see membership.

Topics: mysql, aurora, database-migration, aws-dms, zero-downtime, data

Related case studies

Browse all case studies