The read wall
Almost every web app reads far more than it writes: one user posts a comment, thousands load the page. Sooner or later the single database instance saturates, and the first instinct, renting a bigger one, has a doubling price at every step (lesson 3-1's catalog) and a hard ceiling at the top of the catalog. Engineers hit this wall at real companies constantly, and this lesson is the standard first answer.
A read replica is a second database instance that RDS keeps as a continuously-updated copy of the primary, fed by replication: every change to the primary is shipped to the replica and re-applied there. The replica gets its own endpoint and serves read queries only. All writes still go to the one primary, which is what keeps the data consistent.
Your app then splits its traffic: writes and must-be-fresh reads to the primary's endpoint, everything else (dashboards, search pages, reports) to the replicas. RDS supports several replicas per primary, and you can add them without downtime.
The sizing arithmetic that motivates replicas
An app pushes 900 reads and 100 writes per second at a database instance that handles about 400 queries per second.
reads=900 writes=100 capacity=400 echo "one instance, $((reads + writes)) queries/s against $capacity capacity: overloaded" replicas=$(( (reads + capacity - 1) / capacity )) echo "fix: $replicas read replicas share the $reads reads/s" echo "the primary keeps only the $writes writes/s: fine"
Output
one instance, 1000 queries/s against 400 capacity: overloaded fix: 3 read replicas share the 900 reads/s the primary keeps only the 100 writes/s: fine
The replica count uses (reads + capacity - 1) / capacity, which is integer division rounded up. 900 reads at 400 each needs 2.25 instances, and you cannot rent a quarter of one, so the answer is 3.
Note the shape of the fix: the writes were never the problem. 100 writes per second sits comfortably inside a 400 capacity, so the primary is fine once the reads move elsewhere. Recognizing which half of the traffic is actually saturating a database is the difference between adding replicas and paying for a much larger primary that does not help.
Lag, and replica versus standby
Replication to read replicas is asynchronous: the primary confirms a write to your app first and ships it to replicas a moment later. That gap is replication lag, usually well under a second, sometimes seconds under load. Design around it: any read that must reflect a write the same user just made goes to the primary.
Do not confuse a replica with the Multi-AZ standby from lesson 6-1, because they answer different questions:
| Multi-AZ standby | read replica | |
|---|---|---|
| exists for | availability (surviving an AZ failure) | read scale |
| serves queries? | no, idle until promoted | yes, reads |
| replication | synchronous (no lag) | asynchronous (lag) |
Production databases commonly run both. Replicas have one more career: a replica can be promoted to a standalone primary, and a replica in another region doubles as a disaster-recovery copy and a low-latency read point for far-away users (lesson 1-2).
Why a fresh write can read back stale
The cause is replication lag: the read hit the replica before the asynchronous copy of that write arrived.
Asynchronous replication means the replica is always slightly behind, usually by milliseconds, occasionally by more under load. The write is safe on the primary, and the replica is not broken. It simply had not applied that change yet when the page loaded.
The standard pattern follows directly. Route reads that must see the user's own fresh writes to the primary, and let replicas serve everything that tolerates a moment of staleness.
In practice this means classifying reads rather than routing them all one way. A profile page immediately after an edit goes to the primary, while a dashboard, a search page, or a report is happy on a replica and takes real load off the primary by being there.
What a dashboard should read from
The dashboard should read from a read replica.
The Multi-AZ standby is synchronous but invisible. It accepts no connections at all until a failover promotes it, so pointing anything at it is not a configuration you can even express. That is by design: a standby that served queries would have its own load profile and might not be ready when it is needed.
A read replica exposes its own endpoint precisely so you can point read-heavy workloads at it. Moving the dashboard's heavy SELECT queries there takes load off the primary without touching availability, and the two mechanisms keep working independently.
The confusion is common enough to be worth a rule: the standby is for surviving a failure, and the replica is for spreading reads. Paying for one does not give you the other.