Synchronous Replication and Quorum Commit
By default PostgreSQL replication is asynchronous: a primary commits once its own WAL is durable, without waiting for any standby. If the primary then fails before a standby received the latest WAL, those last transactions are lost. Synchronous replication makes the primary wait for standby confirmation before reporting commit success, eliminating that data-loss window — at the cost of commit late
The one thing to understand first
By default PostgreSQL replication is asynchronous: a primary commits once its own WAL is durable, without waiting for any standby. If the primary then fails before a standby received the latest WAL, those last transactions are lost. Synchronous replication makes the primary wait for standby confirmation before reporting commit success, eliminating that data-loss window — at the cost of commit latency.
Synchronous replication trades latency for durability — but if you don't provision enough standbys, it secretly also trades away availability: the same "wait for confirmation" that prevents data loss will hang every commit when there's no one left to confirm.
Layer 3 — Watch it happen on your own database
One catalog tells you which standbys are actually counting toward your durability guarantee:
SELECT application_name, sync_state, sync_priority, state, replay_lsn
FROM pg_stat_replication;
-- sync_state: 'sync', 'potential' (standby), or 'async'
SHOW synchronous_standby_names;A standby listed in synchronous_standby_names shows sync_state = sync; spares waiting to be promoted into the quorum show potential; everything else is async. If you expect a synchronous standby and see only async rows, your zero-data-loss guarantee is not actually in force — and commits may be silently running async or about to block.
Layer 4 — The levers this hands you
Two GUCs give you fine control over the durability/latency/availability balance. First, synchronous_commit sets how much confirmation each commit waits for — and it is per-transaction settable, so most traffic can run async while only critical writes demand more:
- off — don't even wait for local disk flush (fastest, can lose recent local commits on crash).
- local — wait for local WAL flush only; ignore standbys (this is async replication).
- remote_write — wait until the standby has written WAL to its OS (not necessarily fsynced).
- on — wait until the standby has flushed WAL to disk (default meaning of synchronous).
- remote_apply — wait until the standby has replayed the WAL, so a read on that standby sees the transaction (read-your-writes on replicas).
Second, synchronous_standby_names picks which standbys count and how many must confirm — and this is where you defuse the availability trap:
-- FIRST: the named standbys in priority order; the first 1 to confirm counts
synchronous_standby_names = 'FIRST 1 (s1, s2, s3)'
-- ANY: any 2 of the listed standbys must confirm (quorum commit)
synchronous_standby_names = 'ANY 2 (s1, s2, s3)'- The availability trap: if the required number of synchronous standbys are unavailable, commits block — the database appears to hang. With
FIRST 1 (s1)and one standby, losing it stops all writes. - The fix is enough nodes: at least three with
ANY 1 (s1, s2)orANY 2 (s1, s2, s3), so one standby can fail without blocking commits while still guaranteeing the data is on a second machine. - FIRST k prefers specific standbys by priority; ANY k is more resilient because no single standby is mandatory.
- Place synchronous standbys with low network latency to the primary; cross-region sync is painful.
Layer 5 — What an Oracle DBA should expect vs what they get
Synchronous replication maps onto Data Guard's protection modes, with quorum commit as the notable addition:
- **
synchronous_commit = on≈ Data Guard SYNC (Maximum Availability),** andremote_apply≈ real-time apply where the standby is query-consistent — but in Postgres you choose this per transaction, not just per-database. - The availability trap is the same lesson as Maximum Protection mode: Oracle's Maximum Protection will shut down the primary if no standby can confirm. Postgres instead blocks commits — equally an outage if you lack quorum. Both demand spare standbys.
- **Quorum commit (
ANY k) has no direct classic Data Guard analogue** — it is closer to the quorum model of Oracle's far-sync/observer setups, and it is the recommended way to get zero-loss without a single mandatory standby. - No separate licence. Synchronous replication and quorum commit are built in and free, unlike the editions/options gating around Oracle's higher protection modes.
Key takeaway
Synchronous replication eliminates the data-loss window by making the primary wait for standby confirmation, with synchronous_commit choosing how strong the wait is and synchronous_standby_names choosing who confirms. The trap is that requiring confirmation from too few standbys turns durability into an availability liability — use ANY k quorum with enough spare standbys so one failure never blocks commits, and reserve the strictest levels for transactions that truly need zero loss.
Interview lens
How this shows up in interviews
What an interviewer is actually testing, the same mechanism seen from three roles, and the gap between a shallow answer and one that shows real depth.
What the interviewer is testing
Whether you understand the durability-vs-latency tradeoff of synchronous replication and quorum vs priority configuration.
Questions you should be able to answer
- ▸What does synchronous replication guarantee, and what does it cost?
- ▸Explain synchronous_standby_names quorum (ANY k) vs priority (FIRST k).
- ▸What happens to commits if the required sync standby disappears?
Database engineer
You configure ANY k (quorum) across standbys and choose the synchronous_commit level (remote_write/on/remote_apply) to balance durability against latency.
Software engineer
You know a synchronous commit blocks until a standby confirms, so losing all sync standbys can stall writes — and you plan for it.
Feature builder
You reserve synchronous replication for transactions that truly can't be lost, not the whole workload.
Shallow answer
'Synchronous means the standby is always up to date.' Misses the commit-latency cost and the stall risk.
Answer that shows depth
Async replication commits once the primary's WAL is durable, risking loss of the last transactions if the primary dies before a standby receives them. Synchronous replication makes the primary wait for standby confirmation before returning COMMIT, closing that window — at the cost of a network round-trip of commit latency. synchronous_standby_names sets policy: FIRST k (priority) or ANY k (quorum) of the listed standbys must confirm; synchronous_commit chooses how far (remote_write, on = flush, remote_apply). The catch: if the required standbys are unavailable, commits block, so you size the quorum so a single node loss doesn't stall writes.
Pro lab notebook
The captured run behind every query
Every SQL query above is real and the source citations are verified. Pro unlocks the captured psql output — each query re-run against a real PostgreSQL 17.10 lab, with its verbatim result.
1 real lab transcript for this lesson
The explanation and the SQL above are free — so are the verified source citations. What Pro unlocks is the proof: every query in Synchronous Replication and Quorum Commit re-run against a real PostgreSQL 17.10 instance, with its verbatim psql output captured line for line.
What Pro unlocks here
- Every query in this lesson re-run against a real PostgreSQL 17.10 lab
- The verbatim psql output — page headers, row versions, plan nodes, catalog rows
- The corrected form of any query the source lesson got wrong, re-captured
- A copy-ready notebook you can replay yourself to confirm every claim
How this was verified
This explanation is anchored to PostgreSQL's source tree — the files linked above, on the REL_17_STABLE branch — and cross-checked against the official documentation for versions 15 through 18. Every SQL query shown was executed and its output captured in a throwaway PostgreSQL 17.10 lab; where a query needed correcting to run, that correction is noted inline.
Official documentation: §27.2.8 Synchronous Replication