VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
What Replicas Are For
- Read scaling. Dashboards, search, exports, and API reads move off the source, which keeps its capacity for writes.
- Isolation for expensive queries. The analyst’s 40-second aggregation runs on a replica and blocks nobody.
- A warm standby. A current replica can be promoted when the source fails.
Routing Reads
MySQL does not route queries for you. Something in your stack must send writes to the source and chosen reads to replicas:- Application-level routing. Most frameworks support it directly (Django database routers, Rails
connects_to/roles, Laravel read/write connections). Simple and explicit; the application decides per query. - A proxy. ProxySQL and similar route by statement type or rule, so applications keep one connection string. This also centralizes failover.
Replication Lag: The Actual Hard Part
Replication is asynchronous by default. Commit on the source returns before replicas apply the change, so a replica read a moment later can miss a write that already succeeded. Measure lag from the replica:Seconds_Behind_Source field is the standard signal. It is usually near zero and spikes under bursts of writes, large transactions, and schema changes. Alert on it, and know your tolerance per read path.
The classic failure is read-your-own-writes: a user saves a profile (write to source), the next page loads it from a replica, and the replica has not applied the write yet. The user sees their change vanish. Standard mitigations, cheapest first:
- Pin after write. After a session writes, route that session’s reads to the source for the next few seconds. Many frameworks and proxies support this pattern directly.
- Route by tolerance. Money balances and just-edited pages read from the source; browse pages, search, and analytics read from replicas.
- Session consistency via GTIDs. After a write, capture the transaction identifier and have the replica read wait for it with
WAIT_FOR_EXECUTED_GTID_SET(). Precise, at the cost of plumbing the GTID through the request.
Two Practical Rules
- Replicas should be superset hardware, not leftovers. A replica slower than the source falls behind under exactly the load that made you add replicas.
- Rehearse promotion. A replica you have never promoted is a backup you have never restored. Practice the failover path before you need it.
See also
- Replication basics — setting up the replication this guide builds on
- Binary logging — the log stream replicas replay
- Connection pooling — pooling per role once reads and writes split

