Skip to content

Aurora vs RDS for production Postgres / MySQL — when the premium earns its keep

Compare Amazon Aurora with Amazon RDS so you can tell which one fits your production Postgres or MySQL database. You will learn how to measure failover time, read replica lag and storage I/O on your current setup before you commit to a migration.

This guide compares Amazon Aurora with Amazon RDS (Relational Database Service) for teams running a production Postgres or MySQL database on AWS. Both run real Postgres or MySQL, but Aurora swaps the storage underneath for a distributed layer and charges more per hour for it. The question that keeps coming back is whether the production database should move, and whether that premium buys anything you actually need. Aurora earns it when failover (the switch to a standby database after the main one fails) has to finish in seconds, or when several read replicas (copies that answer read-only queries) carry real traffic. RDS keeps doing the job for a steady, well-tuned workload, and the checks below let you decide from your own failover time, replica lag and storage I/O numbers.

What’s happening

Aurora and RDS share an engine line — both run real Postgres or real MySQL — but the storage layer underneath is different, and that difference drives most of the operational properties.

RDS architecture. A single writer instance with an attached EBS volume. Multi-AZ adds a standby instance with synchronous block-level replication via the storage layer (not Postgres / MySQL replication). Failover swaps the DNS endpoint to the standby. Read replicas use engine-native replication (Postgres streaming replication, MySQL binlog). Storage is provisioned (you pick a size), with autoscaling available up to a limit.

Aurora architecture. The cluster has a writer and optionally up to 15 reader instances. Underneath them is the Aurora cluster volume — a distributed storage system that keeps six copies of the data across three AZs, with quorum-based writes (4 of 6) and reads (3 of 6). The writer streams redo log records to the storage layer, not full data pages. Readers query the same shared volume; they do not replay binlogs. Failover promotes a reader, which is fast because the reader already sees the same storage. Storage is pay-per-GB-used with no provisioning.

The operational consequences flow from those architectures:

PropertyRDS Multi-AZAurora
Failover time30–90s (DNS + standby promotion)10–30s (reader promotion on shared storage)
Replication mechanismBlock-level sync to standby; engine-native to read replicasStorage-layer quorum (6 copies, 3 AZs)
Read replica freshnessAsync, seconds of lag under loadAsync, single-digit ms lag typical
Max read replicas5 (Postgres), 15 (MySQL)15 readers, all on same cluster volume
Storage scalingProvisioned, autoscale to limitPay-per-GB-used, no provisioning
Storage durabilityEBS (single AZ + Multi-AZ standby)6 copies across 3 AZs, always
Storage IOPS pricingProvisioned IOPS or gp3 baselinePer-million-IO, no provisioning
BackupSnapshot to S3Continuous to S3, point-in-time always
Failover blast radiusStandby in another AZAny reader in any AZ
Engine versionStock Postgres / MySQLAurora-flavored Postgres / MySQL
Serverless optionNoAurora Serverless v2 (autoscale ACU)
Major version upgradesRDS handles in-placeAurora handles in-place
Cost shape (compute)Roughly equivalent per-vCPU20–30% premium per-vCPU
Cost shape (storage)Provisioned GB + provisioned IOPSPay-per-GB-used + per-IO

The Aurora storage model is the architectural difference that drives the value proposition. Because readers see the same physical volume as the writer, adding a reader is a compute-only action — no full restore, no warm-up time waiting for the replica to catch up. The same property means failover is fast: the promoted reader does not have to replay anything, it just starts accepting writes against a storage layer it was already reading from.

The per-engine differences matter. Aurora Postgres lags stock Postgres by a major version or two for new features, but offers Aurora-specific features like Babelfish (TDS protocol for SQL Server clients), Global Database, parallel query, and faster minor-version patching. Aurora MySQL diverges further from upstream MySQL — the MySQL 8.0 compatibility level is the current track, with Aurora-specific extensions and some gaps. If the application depends on a Postgres 17 feature that Aurora has not picked up yet, Aurora is not a current option.

Aurora Serverless v2 changes the cost shape for variable workloads. The cluster scales ACU (Aurora Capacity Units) automatically from a minimum to a maximum, in half-ACU increments, with no connection-drop required to scale. A workload that idles overnight and bursts during business hours can run at 1 ACU off-hours and 16 ACU at peak. The catch: Serverless v2 still pays per-ACU per-hour at a rate higher than provisioned Aurora, so a workload that runs at near-peak most of the day spends more on Serverless v2 than on provisioned.

How to verify

Two questions decide most Aurora-vs-RDS migrations.

Is the failover budget tight? If the application can tolerate 60–90 seconds of write unavailability during a Multi-AZ failover, RDS is fine. If the SLA requires sub-30-second recovery, Aurora’s faster failover is material. Measure the actual failover time on the existing RDS:

# Force a failover during a maintenance window and measure
aws rds reboot-db-instance \
  --db-instance-identifier prod-db-1 \
  --force-failover

Watch CloudWatch DatabaseConnections and the application’s error rate around the reboot. The window from first-error to clean-recovery is the real failover budget.

Does the workload need read scale-out that lags less than a second? A reporting workload that runs against an RDS read replica, sees lag in the 1–10 second range, and tolerates stale data, has no need for Aurora. A reporting workload that runs against a read replica and needs near-real-time data — typically because the application reads-its-own-writes from a different endpoint — benefits from Aurora’s millisecond-lag readers.

Check the read replica lag on the existing RDS:

aws cloudwatch get-metric-statistics \
  --namespace AWS/RDS \
  --metric-name ReplicaLag \
  --dimensions Name=DBInstanceIdentifier,Value=prod-db-1-replica \
  --start-time $(date -u -v-7d +%Y-%m-%dT%H:%M:%S) \
  --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
  --period 60 \
  --statistics Maximum \
  --query 'Datapoints[].Maximum' \
  --output text | sort -n | tail -5

If the worst-case lag in a week is 30+ seconds, the application either tolerates that (Aurora is not buying anything for read freshness) or it does not (Aurora’s tighter replication is real value).

Check storage I/O cost shape on the current RDS. Aurora charges per-million-IO. Workloads with very heavy I/O (large sequential scans, full-table updates, frequent vacuum operations) can pay more for storage on Aurora than on RDS with provisioned IOPS gp3:

aws cloudwatch get-metric-statistics \
  --namespace AWS/RDS \
  --metric-name ReadIOPS \
  --dimensions Name=DBInstanceIdentifier,Value=prod-db-1 \
  --start-time $(date -u -v-30d +%Y-%m-%dT%H:%M:%S) \
  --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
  --period 3600 \
  --statistics Sum \
  --query 'Datapoints[].Sum' \
  --output text | paste -sd+ - | bc

The total IO over 30 days, multiplied by Aurora’s per-million-IO rate in the target region, gives you the storage I/O premium. For OLTP workloads (small random IO, mostly buffered) the cost is modest. For analytical workloads on the OLTP database, it can be the dominant line.

The fix

Pick Aurora when at least two of these are true:

  • Failover time is part of the SLA. Sub-30-second recovery is a stated requirement, not just a wish.
  • Read scale-out is part of the architecture. The application uses multiple read replicas and the lag matters.
  • Storage is variable. The database is growing fast or shrinking, and over-provisioning EBS is expensive.
  • Aurora Global Database is on the roadmap. Cross-region read replicas with sub-second lag are an Aurora-only feature.
  • The workload is bursty. Aurora Serverless v2 fits a daily peak / off-hours idle pattern.

Pick RDS when:

  • The workload is steady-state and well-tuned on a known instance size.
  • The Postgres version requirement is newer than what Aurora ships.
  • The I/O cost calculation comes out unfavorable on Aurora.
  • Multi-AZ failover times of 30–90 seconds are acceptable.
  • The team is on a tight budget and the Aurora premium is not justified by the value.

Three things that go wrong in Aurora migrations:

Underestimating the per-IO line. A team that ran on RDS with provisioned IOPS budgeted Aurora at compute + storage and forgot the per-IO charge. The per-IO line for a heavy OLTP workload can be 30–50% of the storage line on Aurora. Use the IO calculation above to forecast.

Treating Aurora as drop-in for Postgres. Some Postgres extensions are not available on Aurora; some configuration parameters are managed by Aurora and not user-tunable. Run the application against an Aurora staging cluster before committing — the extension list and parameter group review takes a day and saves a week of post-migration debugging.

Ignoring the engine-version cadence. Aurora picks up new Postgres major versions 6–12 months after upstream. A migration plan that depends on a Postgres feature released last month against the Aurora roadmap will stall.

The migration mechanics for an RDS-to-Aurora cutover use the aws rds restore-db-cluster-from-snapshot path (for greenfield) or the read-replica-promotion path (for in-place migration with low downtime). The read-replica path: create an Aurora read replica of the RDS instance, let it catch up, promote it during a maintenance window. Total write-downtime is typically 30–90 seconds — the same window as a Multi-AZ failover — assuming the application can handle the brief cutover.

Aurora is the right default for new production SaaS workloads in 2026. RDS is the right default for stable existing workloads where the migration cost outweighs the operational benefits.


Stack Harbor designs and operates production RDS / Aurora topologies as part of Managed AWS and the ongoing Managed Cloud Ops layer. If your database posture is “Multi-AZ checkbox + hope,” start with an infrastructure consult.