RDS vs Aurora, and How Failover Works
Introduction¶
Both are managed relational databases (MySQL/PostgreSQL-compatible). The difference is architecture, and it drives failover behaviour, read scaling, and price.
RDS (standard)¶
A managed EC2 instance running MySQL/PostgreSQL/etc. with EBS storage.
- Multi-AZ instance: a synchronous standby in another AZ, its own storage. On failure, RDS flips the DNS CNAME to the standby. Failover ~60–120s (detection + DNS + the standby warming up).
- Multi-AZ DB cluster (newer): one writer + two readable standbys, semi-sync, failover ~35s, and the standbys serve reads.
- Read replicas: asynchronous, separate storage, can be promoted manually (not automatic failover). Cross-region possible.
Aurora¶
Compute instances are stateless; data lives in a distributed storage layer that spans 3 AZs with 6 copies, quorum writes (4/6), and self-healing. Instances attach to that shared volume.
- Writer + up to 15 readers, all on the same storage — replica lag is typically < 10 ms (they read the same volume, not a replication stream).
- Failover: a reader is promoted to writer. No data copy needed (shared storage). ~30s or less, often ~10–15s. With no reader, Aurora creates a new instance (slower).
- Endpoints:
- cluster endpoint → always the current writer.
- reader endpoint → load-balances across readers.
- instance endpoints → a specific node (avoid hardcoding).
- Aurora Serverless v2: compute autoscales in fine increments.
- Storage autogrows; you pay for what's used + I/O (or I/O-Optimized flat rate).
What breaks during a failover (both)¶
- In-flight transactions are rolled back. The app sees connection errors.
- Existing connections to the old writer are severed. The pool must reconnect — to the new writer, which means re-resolving the endpoint (don't cache the IP; honour DNS TTL, ~5s for Aurora).
- ~10–40s of write unavailability. Reads via the reader endpoint may continue (Aurora) or also blip (RDS single standby).
- Cached prepared statements / session state on the old connection are gone.
Designing the app to survive it¶
- Use the cluster/writer endpoint, never an instance endpoint or IP.
- Connection pool: short
max lifetime(e.g. 15 min), validation on borrow, and a fast acquire timeout so requests fail rather than hang. - Retry writes with backoff on connection errors / "read-only" errors (you briefly hit a demoted node). Make the writes idempotent.
- Separate read traffic to the reader endpoint so reporting doesn't compete with transactional load — and so reads survive a writer failover.
- AWS JDBC/driver wrappers (Aurora) detect failover fast and re-route, faster than waiting for DNS.
- Test it:
aws rds failover-db-clusterin staging and watch your error rate.
Choosing¶
| Need | Pick |
|---|---|
| Lowest cost, modest load, simple | RDS single-AZ (dev) / Multi-AZ (prod) |
| Fast failover + read scaling + MySQL/PG compat | Aurora |
| Spiky / unpredictable load | Aurora Serverless v2 |
| Exotic engine (Oracle, SQL Server, MariaDB) | RDS (Aurora is MySQL/PG only) |
| Cross-region DR | Aurora Global Database, or RDS cross-region read replica |
Verification and troubleshooting¶
aws rds describe-db-clusters --db-cluster-identifier mydb \
--query 'DBClusters[].{Writer:Endpoint,Reader:ReaderEndpoint,Members:DBClusterMembers}'
aws rds failover-db-cluster --db-cluster-identifier mydb # test
- App errors for 60–120s on RDS failover — expected for single-standby Multi-AZ. Move to Aurora or Multi-AZ DB cluster for ~30s, and add write retries.
- After failover, writes fail "read-only" / "cannot execute ... in a read-only transaction" — the app reconnected to the old writer (now a reader) because DNS was cached. Lower the pool's connection lifetime; don't cache the resolved IP.
- Reader endpoint returns stale data — replica lag spiked (a big write
burst, or a long-running reader query holding a snapshot). Check
AuroraReplicaLag. - Failover took minutes — no reader existed, so Aurora had to launch a new instance. Keep at least one reader for prod.
- Connections pile up on one reader — the reader endpoint load-balances on new connections only; long-lived pooled connections stick. Recycle connections periodically.
- Cross-AZ data transfer cost surprise (RDS) — app in AZ-a talking to a DB writer in AZ-b. Aurora's storage is cross-AZ by design; for RDS, co-locate or accept it.
Related tools and reading¶
- On-site: Port Checker.
- Related posts: Connection pooling explained, Disaster recovery: RPO and RTO.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Cloud & AWS
AWS WAF: The Rules That Matter
AWS WAF filters HTTP requests at the ALB/CloudFront/API Gateway edge. Here's a sensible baseline Web ACL, how to tune with count mode, and the false-positive traps.
October 24, 2026An S3 Static Site Behind CloudFront
The right way to host a static site on AWS: a private S3 bucket, CloudFront with OAC in front, HTTPS via ACM, and SPA fallback routing. Plus the 403s that trip everyone.
October 24, 2026CloudWatch Logs and Metric Filters
CloudWatch Logs is cheap to write and expensive to forget about. Here's retention, turning error patterns into metrics and alarms, and Logs Insights for ad-hoc queries.
October 24, 2026