Skip to main content
RunBook Academy

PostgreSQLXV · High Availability, Failover and Disaster RecoveryHA

Split-brain and why fencing is not optional

Advanced⏱ ~35 minpsql

What you'll learn

  • Describe how split-brain arises and why PostgreSQL cannot prevent it
  • Explain what resolving a split-brain costs
  • Compare fencing mechanisms by what they actually guarantee
  • Order a failover so fencing precedes promotion

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

Split-brain is two nodes both believing they are the primary, both accepting writes. It is the worst outcome a failover can produce, and it is easy to cause by accident.

Creating one

Everything below was done on purpose, on a working pair, to measure the cost.

Data-loss riska promotion with the old primary left running
$ -- rbpg-sb was promoted. rbpg-prim was NOT stopped.
-- 120 rows written to the old primary, 300 to the new one.
SELECT origin, count(*) FROM ha GROUP BY origin ORDER BY origin;
--- old primary (timeline 1) ---     --- new primary (timeline 2) ---
 origin    | count                  origin    | count
-------------+-------              -------------+-------
OLD-PRIMARY |   120               NEW-PRIMARY  |   300
primary     |   500               primary      |   500
Read-only / Safeneither knows the other exists
$ -- on the old primary
SELECT count(*) FROM pg_stat_replication;
SELECT pg_is_in_recovery();
-- on the new primary
SELECT pg_is_in_recovery();
 count             pg_is_in_recovery      pg_is_in_recovery
-------           -------------------    -------------------
   0            f                      f

Both writable. Both healthy by every internal measure. No error anywhere.

How it happens by accident

The deliberate version above required leaving the old primary running. The accidental versions require nothing at all:

A network partition. The standby cannot reach the primary and concludes it has failed. Clients on the primary’s side of the partition carry on writing to it. Nothing has crashed; the network is simply divided.

A slow primary. Heavy load, a long checkpoint, an unresponsive disk. Health checks time out; the primary is alive and serving.

A promotion during maintenance. The primary is stopped for a restart. A monitoring system notices and promotes. The primary restarts and resumes accepting writes.

Two failovers. An HA stack fails over, then fails over again before the first old primary was cleaned up.

Every one of these produces two writable clusters, and clients arrive at whichever one their connection string, DNS cache or proxy sends them to.

What resolving it costs

Data-loss riskafter pg_rewind rejoined the old primary to the new one
$ SELECT origin, count(*) FROM ha GROUP BY origin ORDER BY origin;
   origin    | count
-------------+-------
NEW-PRIMARY |   300
primary     |   500

-- the 120 'OLD-PRIMARY' rows are gone

Fencing

Fencing means making certain the old primary cannot accept writes, before promoting anything. Mechanisms, ordered by what they actually guarantee:

MechanismGuaranteeWeakness
Power off (IPMI, PDU, hypervisor)AbsoluteNeeds out-of-band access that works when things are broken
Revoke storage (SAN, iSCSI, cloud volume detach)AbsoluteStorage-layer dependent
Leader lease with self-demotionStrong, fails closedRequires a consensus store
Network isolation (firewall, security group)StrongThe change must reach the switch or API
Stop the service (pg_ctl stop, systemd)WeakRequires the node to be reachable and cooperative
HopeNoneCommon

The pattern is that the reliable mechanisms do not require the failing node’s cooperation, and the unreliable ones do. A node that is unreachable enough to need fencing is unreachable enough that you cannot ask it to stop.

The ordering that matters

Fence, verify the fence, then promote.

1. Detect        the primary appears to have failed
2. FENCE         make certain it cannot write
3. VERIFY        confirm the fence took effect
4. Promote       pg_promote() on the standby
5. Reroute       point clients at the new primary
6. Rejoin        pg_rewind or rebuild the old primary

Step 3 is the one that separates a procedure from a hope. “I issued a shutdown command” is not verification; “the host does not respond to ping and the hypervisor reports it powered off” is.

If you cannot fence and cannot verify, the correct action is to not promote. An outage where the data is intact is recoverable. A split-brain is not.

That is a genuinely hard call to make at three in the morning with people asking when the site will be back, which is precisely why it belongs in a written runbook decided in advance, rather than in somebody’s judgement during the incident.

What to take from this

  • Split-brain was created on a live pair with no error from PostgreSQL: two writable clusters, neither aware of the other.
  • Resolving it discarded 120 committed, acknowledged rows, permanently. That is the definition of rejoining, not a bug.
  • Manual reconciliation is not generally solvable — conflicting keys, overlapping sequences, broken references.
  • Reliable fencing does not require the failing node’s cooperation.
  • The leader lease is the one self-fencing that works, because it fails closed.
  • Fence, verify, then promote. If you cannot verify, do not promote.
  • Synchronous replication bounds failover data loss; it does not prevent split-brain.

Cross-course references

  • Linux for Production Sysadmins — Part LIII (Quorum and split brain) and Part LIV (Fencing and STONITH) cover the mechanism PostgreSQL deliberately does not provide, and why an unfenced failover is a coin toss.
  • Ceph & Distributed Storage — Part IX (Monitor quorum) and Part CXVI (Network partition) cover the same problem in a system that does implement quorum, which is a useful contrast.
  • Kubernetes for Production Sysadmins — Part LXVII (etcd quorum) covers the quorum an operator-managed PostgreSQL borrows.

Quiz

Knowledge check · 6 questions

  1. Q1. After a split-brain is resolved with pg_rewind, what happens to transactions committed on the losing node?

  2. Q2. A synchronous standby is promoted during a network partition. The old primary's commits are blocking on SyncRep. An operator clears the block to restore service. What has just happened?

  3. Q3. Why is a leader lease with self-demotion considered strong fencing while 'stop the service' is considered weak?

  4. Q4. Which circumstances can produce split-brain without anyone acting carelessly? Select all that apply.

  5. Q5. If the old primary cannot be fenced and the fence cannot be verified, the correct action is to promote anyway to restore service.

  6. Q6. Why must fencing precede promotion, and what does 'verify the fence' mean in practice?

Passing score: 75%. Answers are checked in this browser.