PostgreSQL Failover: What Actually Breaks During a Promotion
A practical look at what goes wrong in real PostgreSQL HA setups — and why failover is rarely as seamless as diagrams suggest
PostgreSQL failover often looks reassuring on architecture diagrams.
A primary node goes down. A replica is promoted. Traffic switches. The system recovers.
In real production environments, this sequence is rarely so clean.
Failover is not a single event. It is a chain reaction that unfolds across databases, connection pools, load balancers, and applications. Most outages happen not because PostgreSQL fails to promote a replica, but because something around it behaves in an unexpected way.
Understanding what actually breaks during a failover is the difference between a system that recovers predictably and one that enters a prolonged incident.
Failover Is a Distributed Systems Problem
PostgreSQL itself is usually not the weakest link during failover.
The promotion mechanism works reasonably well. The real complexity appears outside the database. Client connections, pooling layers, routing components, and application logic all react to failure at different speeds and with different assumptions.
Failover forces all these layers to change state at the same time. If even one of them lags behind or makes the wrong assumption, availability quickly turns into instability.
This is why failover problems often look random while being completely deterministic.
The First Thing That Breaks: Client Connections
When a primary node disappears, existing connections do not fail gracefully.
Active transactions are aborted. TCP connections are dropped. Clients receive errors that they may never have encountered before. Many applications implicitly assume that database errors are rare and exceptional. During failover, they are guaranteed.
The real danger is not the error itself, but how the application reacts to it. Some clients retry blindly. Others retry inside broken transactions. Some reuse connections that are already dead. Each of these behaviors can amplify a short failover into a full application outage.
A database that fails over correctly can still take the system down if clients are not prepared for transient failure.
Connection Poolers Can Either Help or Make It Worse
PgBouncer often becomes the scapegoat when failover misbehaves. In practice, the problem is rarely PgBouncer itself. It is how it is configured.
Session pooling keeps connections open across multiple transactions. During failover, those connections may survive long enough to talk to the wrong node or operate under outdated assumptions. This creates confusing behavior where queries appear to succeed but do the wrong thing.
Transaction pooling behaves very differently. Connections are reset at transaction boundaries, which makes role changes visible much faster. Old connections are discarded instead of reused. In high-availability environments, this difference is critical.
Most unpredictable failover behavior involving PgBouncer can be traced back to session pooling being used where it should not be.
Promotion Does Not Mean Readiness
A promoted replica is not immediately ready to serve production traffic.
After promotion, PostgreSQL must stop WAL replay, switch timelines, initialize background workers, and reconcile internal state. Extensions may need time to stabilize. Replication slots may need to be recreated or reassigned.
Routing traffic too early is a subtle but common mistake. Writes may appear to succeed while not being fully durable. Reads may return inconsistent results. These issues are especially hard to detect because they often disappear on their own minutes later.
Failover is not finished when the replica becomes primary. It is finished when the new primary is stable.
Replication Slots Fail Quietly
Replication slots are another source of delayed failure.
After promotion, slots that were tied to the old primary may remain orphaned. WAL files begin to accumulate silently. Disk usage grows slowly until an alert fires hours or days later, often during peak traffic.
Because this failure mode is delayed, it is rarely associated with the original failover event. Teams treat it as a separate incident, even though the root cause is the same.
Slots must be explicitly managed during failover, either by automation or by a cluster manager that understands their lifecycle.
Load Balancers Often Ask the Wrong Question
Many routing layers rely on simple checks. If a node accepts connections or responds to a basic query, it is considered healthy.
During failover, this logic breaks down.
A node can accept connections and still be the wrong target for writes. A replica can respond to queries while being seconds away from promotion. A promoted primary can appear alive before it is actually safe to use.
Reliable routing requires role awareness, not just liveness checks. Without that, traffic switching during failover becomes guesswork.
DNS Rarely Saves You
DNS-based failover looks elegant on paper.
In practice, caching behavior is unpredictable. TTLs are ignored. Clients hold onto old IPs longer than expected. Failover speed becomes inconsistent across different parts of the system.
By the time DNS changes propagate, retries may already be exhausted and users may already notice the outage. DNS works well for discovery, but it is a poor tool for fast, deterministic failover.
The Most Dangerous Phase Is Recovery
The most fragile moment in a failover is not the outage itself. It is the moment when the system looks like it has recovered.
Teams often re-enable traffic too quickly, reconnect pools before cleanup is complete, or assume that replicas are healthy because monitoring dashboards look green. This is when data divergence and subtle corruption risks appear.
A cautious, deliberate recovery process is far safer than a fast one.
Why Failover Tests Often Mislead
Many teams believe their failover strategy works because they have tested it.
What they usually tested was a manual switchover in a quiet environment. No concurrent writes. No long-running transactions. No retry storms. No real production load.
Failover that works in staging under ideal conditions can still fail badly in production. Real confidence comes only from understanding how systems behave under stress, not from successful demos.
Reliable Failover Is Boring by Design
PostgreSQL failover becomes reliable when it stops being clever.
Predictable behavior comes from clear separation of responsibilities, aggressive cleanup of stale state, role-aware routing, and applications that treat database errors as normal during failure.
Failover is not a feature to showcase. It is a failure mode to survive.
Teams that understand this build systems that behave calmly under pressure. Teams that do not are surprised every time.
At SysRoot.io, we help teams design PostgreSQL HA systems that fail in predictable ways — and recover without drama.