Engineer synchronous commit guarantees deliberately by separating remote write, flush, and apply acknowledgments from availability and application-visible latency.

Synchronous Replication, Quorum Commit, Latency, and Failure Semantics

Engineer synchronous commit guarantees deliberately by separating remote write, flush, and apply acknowledgments from availability and application-visible latency.

Intermediate → Advanced180–240 minutesMulti-node physical replication and HA labCurrent patched PostgreSQL 18.xCore PostgreSQL utilities onlyReplication/owner/admin privileges where explicitly statedDisposable local nodes on ports 55436–55438Third-party HA orchestrators are conceptual onlyLast reviewed: August 2026

Learning outcomes

Asynchronous streaming minimizes commit latency, but a primary failure can lose transactions that the application was told had committed if those WAL records had not reached a usable standby. Synchronous replication changes the commit contract by making selected commits wait for standby acknowledgments. The important question is: which acknowledgment?

01

Explain FIRST priority and ANY quorum standby selection.

02

Map synchronous_commit modes to local commit, remote write, remote flush, and remote apply evidence.

03

Observe sync_state and commit waiting rather than assuming a configured name is active.

04

Inject a controlled standby outage and explain availability behavior.

05

Choose quorum/latency policy from failure tolerance instead of treating synchronous replication as “zero data loss” magic.

Guarantee boundary

Synchronous replication strengthens acknowledgement semantics. It does not automatically perform failover, fence the old primary, route clients, guarantee that every named standby is healthy, or make two sites independent of common storage/network failures.

1. Name the standby explicitly

synchronous_standby_names matches a standby's application_name. If names are duplicated, selection can be indeterminate. Set a deliberate application name in the standby's primary_conninfo and verify what the primary sees.

text · standby recovery connection identity pattern
primary_conninfo = 'host=localhost port=55436 user=ch14_repl application_name=servicehub_sync1'primary_slot_name = 'ch14_standby_slot'
sql · primary: verify the connected name/state
SELECT application_name, state, sync_state, sync_priority,       write_lsn, flush_lsn, replay_lsnFROM pg_stat_replication;

A standby must reach streaming before it can act as a synchronous standby. Configuration text alone is not proof of protection.

2. FIRST means priority; ANY means quorum

text · priority-based examples
synchronous_standby_names = 'FIRST 1 (servicehub_sync1, servicehub_sync2)'# Wait for one selected standby; earlier names have higher priority.synchronous_standby_names = 'FIRST 2 (servicehub_sync1, servicehub_sync2, servicehub_sync3)'# Wait for the two highest-priority available synchronous standbys.
text · quorum-based example
synchronous_standby_names = 'ANY 2 (servicehub_sync1, servicehub_sync2, servicehub_sync3)'# Wait for replies from any two candidates.

FIRST is useful when topology has preferred nodes. ANY expresses a quorum: any required number of listed candidates may satisfy the commit. Neither syntax tells PostgreSQL to build or repair the nodes.

3. synchronous_commit chooses the acknowledgment depth

The standby can acknowledge at different stages. remote_write waits until the synchronous standby has written the WAL to its operating system, but not necessarily flushed it to stable storage. on waits for remote flush. remote_apply waits until replay has applied the transaction, making it visible to queries on the synchronous standby in simple cases.

Mode Commit waits for What it does not prove
local local durable flush, not synchronous standby remote receipt
remote_write remote OS write acknowledgement remote durable flush / visibility
on remote durable flush replay / query visibility
remote_apply remote replay/application automatic failover or client routing
off asynchronous local acknowledgement behavior local immediate flush or remote receipt
sql · primary: run mode-by-mode transactions
BEGIN;SET LOCAL synchronous_commit = 'remote_write';UPDATE app.ch14_work_orders SET status='dispatched' WHERE work_order_id=14001;COMMIT;BEGIN;SET LOCAL synchronous_commit = 'on';UPDATE app.ch14_work_orders SET status='onsite' WHERE work_order_id=14001;COMMIT;BEGIN;SET LOCAL synchronous_commit = 'remote_apply';UPDATE app.ch14_work_orders SET status='completed' WHERE work_order_id=14001;COMMIT;

Measure latency locally with the same workload and topology. The minimum additional latency depends on network round trips and standby processing; there is no universal millisecond value.

4. Connect the commit mode to observed LSNs

sql · primary: inspect remote acknowledgement positions
SELECT application_name, state, sync_state,       sent_lsn, write_lsn, flush_lsn, replay_lsn,       write_lag, flush_lag, replay_lagFROM pg_stat_replication;

The lag columns estimate how long recent WAL took to reach write, flush, and replay acknowledgement. PostgreSQL documents them as measurements relevant to the corresponding synchronous-commit levels, not catch-up ETA values.

5. Failure injection: commits can wait

Configure the disposable primary to require the only standby, confirm it is sync, then stop the standby. A write transaction using synchronous_commit=on can finish its local work and wait for required standby confirmation. From another primary session, inspect the wait rather than killing random processes.

sql · primary observer: find sessions waiting for standby acknowledgement
SELECT pid, usename, state, wait_event_type, wait_event,       xact_start, queryFROM pg_stat_activityWHERE wait_event = 'SyncRep'   OR wait_event = 'WaitForStandbyConfirmation';

Exact wait-event naming can differ by wait point and version, so interpret both the SQL session state and pg_stat_replication. Restart the standby and observe the blocked commit complete. This is the availability cost of requiring a synchronous acknowledgment.

6. Do not “fix” an outage by silently weakening guarantees

If required synchronous standbys are unavailable, operators sometimes remove them from synchronous_standby_names to restore write availability. That is a business continuity decision that weakens the durability contract. Make it explicit, logged, authorized, and reversible. PostgreSQL cannot decide your acceptable data-loss window.

sql · primary: verify the effective setting and source
SELECT name, setting, context, source, pending_restartFROM pg_settingsWHERE name IN ('synchronous_standby_names','synchronous_commit');
Wrong approach

“Synchronous replication means zero data loss” is too broad. The guarantee depends on the chosen synchronous_commit level, which standbys are actually selected/streaming, common-mode failures, whether a failover candidate contains the acknowledged WAL, and whether failover is correctly fenced and routed.

7. Quorum design requires a failure model

ANY 2 (a,b,c) tolerates loss of one candidate while still satisfying a two-standby quorum, assuming the surviving two are reachable and sufficiently current. FIRST 1 chooses one preferred synchronous node with potential replacements. Across regions, increased round-trip latency may dominate application response time. Keep quorum membership aligned with failure domains; three VMs on one storage system are not three independent durability domains.

8. Verify the synchronous set during topology change

A standby listed in synchronous_standby_names is not automatically synchronous. It must be connected, identified by a matching application_name, and in a state eligible for synchronous selection. During startup or catch-up, it may remain asynchronous/potential. Operational automation should wait for observed state='streaming' and the expected sync_state before declaring the configured durability policy restored.

sql · primary: assert the expected synchronous membership
SELECT application_name, state, sync_state, sync_priority,       flush_lsn, replay_lsn, reply_timeFROM pg_stat_replicationORDER BY application_name;

For ANY quorum, candidates show sync_state='quorum'; for priority-based selection, active synchronous members show sync and later candidates may show potential. Build alerts around the required count and state, not only the GUC string.

9. Acknowledged does not mean promoted

Suppose a transaction returns success under synchronous_commit=on. PostgreSQL has received the required remote durable flush acknowledgments before returning success. If the primary then fails, the HA controller must still promote a candidate that actually has that WAL and fence any competing writer. Synchronous commit narrows the durability uncertainty; orchestration determines whether the protected copy becomes the authoritative service.

Likewise, a client timeout is ambiguous: the server might have committed locally and even synchronously replicated the transaction before the client stopped waiting. Applications need idempotency keys or transaction-result reconciliation rather than assuming “timeout means rollback.” This connects Chapter 07's retry design directly to HA behavior.

sql · ServiceHub idempotency pattern survives ambiguous commit outcome
CREATE TABLE IF NOT EXISTS app.ch14_commands (  request_key text PRIMARY KEY,  work_order_id bigint NOT NULL,  requested_state text NOT NULL,  created_at timestamptz NOT NULL DEFAULT clock_timestamp());INSERT INTO app.ch14_commands(request_key, work_order_id, requested_state)VALUES ('dispatch-14001-v1', 14001, 'dispatched')ON CONFLICT (request_key) DO NOTHINGRETURNING *;

10. Per-transaction durability can be a feature

synchronous_commit can be set per transaction. A system can reserve remote_apply for operations that require immediate replica visibility while using on for most durable writes and asynchronous behavior for explicitly expendable telemetry. The prerequisite is a documented business classification; ad hoc developer overrides turn the durability model into guesswork.

11. Application visibility and causal reads

If an application commits with remote_apply to a selected synchronous standby, that standby has replayed the commit before the primary acknowledges it, which can support read-after-write routing to that standby in simple topologies. With on, the WAL may be durable remotely but not yet visible to standby queries. This is a consistency contract, not simply a performance knob.

Check your understanding

  1. What is the difference between FIRST and ANY?
  2. What does synchronous_commit=on wait for remotely?
  3. Which mode waits for standby replay?
  4. Why can write availability decrease under synchronous replication?
  5. Why is one synchronous VM in the same failure domain not equivalent to an independent durable copy?
Review the answers

FIRST chooses synchronous nodes by priority; ANY waits for a quorum from the candidate set. on waits for remote durable flush. remote_apply waits for replay. Required acknowledgments can block commits when standbys are unavailable. Shared power/storage/network can defeat the assumed independence of copies.

Authoritative references

Replication and HA behavior is topology-, version-, privilege-, and operating-system-sensitive. These primary PostgreSQL sources define the mechanisms used in this lesson.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.