Database reliability engineer monitoring PostgreSQL logical replication and failover readiness dashboards at a multi-screen workstation

Promoting PostgreSQL Is Not Enough: Prove Logical Replication Can Resume

Thu, Sep 17, 2026

A synthetic incident makes the risk concrete. A planned PostgreSQL failover completes, the promoted server accepts writes, application health checks turn green, and most dashboards look normal. One CDC consumer, however, never resumes because its logical replication slot was not actually present and usable on the promoted standby. The database is available; the downstream contract is broken. That distinction is the center of this runbook.

This article uses PostgreSQL 18 as the fixed technical baseline and treats native logical-replication failover as an established capability, not a 2026 launch. The PostgreSQL Global Development Group’s PostgreSQL 17 release announcement, published September 26, 2024 and accessed September 17, 2026, records the introduction of failover controls for logical replication in September 2024. The PostgreSQL 18 logical replication failover documentation, accessed September 17, 2026, describes the current procedure, including the requirement to identify the complete needed slot set and verify that those slots are synchronized to the standby before promotion. Slot synchronization is asynchronous.

The objective is therefore not “promotion succeeded.” It is a defensible proceed, hold, or recover decision based on three separate evidence classes: the expected consumer inventory, the observed standby slot state, and post-promotion downstream reconciliation. A healthy row is evidence about that row; it is not evidence that no expected row is missing.

Define the continuity contract before choosing a promotion

Failover arguments become confused when the word “continuity” is asked to cover five different properties. Source availability is whether a writable PostgreSQL primary exists. Acknowledged-write durability is whether transactions already reported successful to clients survive the physical failover. Consumer restart is whether each logical consumer can resume from a valid position. Duplicate handling is whether replayed changes are safe. Downstream completeness is whether the intended business effects are ultimately present in each target system.

The PostgreSQL 18 logical decoding documentation, accessed September 17, 2026, explains that logical decoding can send recent changes again after a crash because a slot’s current position is persisted at checkpoints; clients are responsible for avoiding harmful effects from repeated messages. That makes duplicate handling a consumer contract, not a property to infer from a synced slot.

Proposed operating model: write the continuity contract before scheduling promotion. The recovery objectives below are team policy choices, not PostgreSQL guarantees.

Contract dimension

Owner

Required evidence

Team-selected objective

Source availability

DBA/platform

new primary writable; old primary fenced

agreed recovery time

Acknowledged-write durability

DBA/incident commander

physical-replication evidence to cutover barrier

agreed loss tolerance

Consumer restart

CDC owner

expected slot exists and is failover-ready; endpoint reconnects

agreed restart time

Duplicate safety

application/data owner

idempotency, dedupe key, or replay procedure tested

no unbounded duplicate business effect

Downstream completeness

data/application owner

bounded event-ledger reconciliation

all expected business transitions accounted for

Unverified assumption: any row in this table without an owner, evidence source, or tested objective remains unknown. Unknown is a hold, not a reason to reinterpret a database-level signal as an end-to-end guarantee.

Pin the versions, topology and promotion boundary

Start with identities, because the most dangerous failover mistakes are boundary mistakes. The physical standby being promoted is not a logical subscriber. A PostgreSQL subscriber may itself be another database cluster, while an external CDC platform may consume a slot and write to Kafka, object storage, a warehouse, a search index, or an application service. Track the publisher database, slot, consumer, and designated physical standby as separate identifiers.

The runbook baseline should record the exact PostgreSQL 18 minor version in use, packaging source, logical output plugin, connector or subscriber version, HA manager, endpoint mechanism, and configuration revision. PostgreSQL’s upstream documentation describes server behavior; it does not certify that a managed provider exposes every setting or that a connector preserves slot state in a particular way. Those are deployment checks. The PostgreSQL 18 failover documentation visible at the research cutoff is versioned independently from PostgreSQL 19 development documentation, so this procedure deliberately does not import PostgreSQL 19 beta behavior.

Inventory field

Example value format

Evidence owner

Promotion significance

Publisher cluster

stable cluster ID

platform

identifies old and new primary

Publisher database

orders_prod

DBA

logical slots are database-associated

Designated standby

stable node ID

DBA/platform

intended promotion target

Logical consumer

subscriber/connector ID

CDC owner

restart and reconciliation owner

Slot name

cluster-wide slot ID

DBA + CDC owner

join key for readiness

Output plugin

pgoutput or deployed plugin

DBA

compatibility dependency

Endpoint

writer DNS/service alias

platform

reconnection and fencing path

Evidence time

UTC timestamp

incident scribe

freshness control

Config revision

commit/change ID

platform

reproducibility

Provider capability

tested/unknown

service owner

outside scope until verified

A major-version replay or upgrade qualification is a different exercise: it asks whether workloads, extensions, drivers and operational tooling behave correctly on a changed software version. Keep that work in a separate PostgreSQL workload-replay readiness exercise. This runbook keeps the software baseline fixed and asks whether the existing logical estate can survive the actual promotion path.

Proposed acceptance rule: topology evidence must be captured from the environment scheduled for the drill, with a named revision and timestamp. A diagram copied from an architecture wiki without a freshness claim is context, not promotion evidence.

Build an expected slot inventory that cannot silently shrink

The expected slot set must originate independently of the standby query used to judge health. Otherwise a deleted or never-created slot can disappear from both the system and the checklist, producing a false green result. Maintain a canonical consumer register with one row per logical consumer or required table-synchronization slot, then compare that register with PostgreSQL observations.

A practical proposed schema is: publisher_cluster, publisher_database, consumer_id, consumer_type, subscription_name, slot_name, slot_kind, failover_required, designated_standby, owner, recovery_method, and inventory_revision. Reject an empty set for a known CDC-enabled publisher, duplicate slot_name assignments, missing publisher database names, or ownerless external consumers unless a reviewed exception explains them.

Validation

Pass condition

Failure meaning

Expected set non-empty

expected consumers represented

discovery or governance gap

Slot names unique

no conflicting assignment

ambiguous ownership

Publisher DB known

every logical slot mapped

incomplete recovery context

Consumer owner known

responder can act

operationally unrecoverable during incident

Failover requirement explicit

yes/no justified

silent scope shrink

Designated standby explicit

one intended target

readiness checked on wrong node

Inventory PostgreSQL subscriptions and table synchronization

For PostgreSQL subscribers, the PostgreSQL 18 logical replication failover procedure, accessed September 17, 2026, says to identify slots for failover-enabled subscriptions on each subscriber that will be served after failover. It also identifies table-synchronization slots that matter only when table copy has reached the documented finished state; other table-sync slots may be dropped or recreated and therefore should not be demanded indiscriminately. The pg_subscription_rel catalog reference, accessed September 17, 2026, defines f as “finished table copy,” followed by synchronized and ready states.

A read-only discovery pass can first record current_database(), subscription name, slot name, subfailover, and enabled state from pg_subscription, then run the documented table-sync discovery logic in every subscriber database containing failover-enabled subscriptions. The point is completeness across databases, not merely obtaining one array of slot names from one node.

Account for external CDC consumers and missing rows

The PostgreSQL 18 failover procedure states that non-PostgreSQL subscribers may use their own mechanisms to identify the slots they use. In a planned failover, the primary-side query for non-temporary failover-enabled slots is a useful cross-check, but it should not replace the independent business-consumer register. A slot can exist without anyone remembering why it exists, and a consumer can be expected even when its slot is missing.

A proposed completeness query should preserve missing rows with a left join:

-- Read-only audit pattern. Replace VALUES with the reviewed expected inventory.
WITH expected(slot_name, database_name, consumer_id) AS (
  VALUES
    ('sub_orders', 'orders_prod', 'pg-subscriber-a'),
    ('cdc_billing', 'orders_prod', 'billing-cdc'),
    ('cdc_search', 'orders_prod', 'search-cdc')
)
SELECT e.consumer_id,
       e.slot_name,
       e.database_name,
       r.synced,
       r.temporary,
       r.invalidation_reason,
       CASE
         WHEN r.slot_name IS NULL THEN 'MISSING'
         WHEN r.synced AND NOT r.temporary AND r.invalidation_reason IS NULL THEN 'READY'
         ELSE 'NOT_READY'
       END AS audit_state
FROM expected e
LEFT JOIN pg_replication_slots r
  ON r.slot_name = e.slot_name
 AND r.database = e.database_name
ORDER BY e.consumer_id;

Expected observation: if cdc_search is absent on the standby, it still appears as MISSING. That row blocks approval until the discrepancy is explained and repaired.

Check synchronization prerequisites and backpressure deliberately

Slot failover is not one switch. The PostgreSQL 18 logical decoding documentation, accessed September 17, 2026, documents a chain of prerequisites for synchronizing logical failover slots to a hot standby. The standby must enable sync_replication_slots; synchronization also requires a physical replication slot between primary and standby through primary_slot_name, hot_standby_feedback enabled on the standby, and a valid database name in primary_conninfo. PostgreSQL highly recommends naming that physical slot in synchronized_standby_slots on the primary so logical consumers cannot advance beyond what the intended standby has received.

Requirement

Evidence to capture

Failure/hold condition

Logical slot marked for failover

subscription/slot property

required slot not failover-enabled

sync_replication_slots on standby

config snapshot

false or unknown

primary_slot_name

standby config + physical slot exists upstream

missing/mismatched

hot_standby_feedback

standby config

disabled where slot sync depends on it

primary_conninfo database

redacted config proof

no valid dbname for slot sync

synchronized_standby_slots policy

primary config

required physical slot omitted or unknown

Separate slot copying from transmission ordering

Automatic slot synchronization is periodic and asynchronous. PostgreSQL also exposes pg_sync_replication_slots, but the logical decoding documentation says that manual function is primarily for testing and debugging, lacks cyclic retries, and should be used cautiously. Do not turn it into an invented production polling design.

The names matter. sync_replication_slots runs synchronization behavior on the standby. primary_slot_name identifies the physical upstream slot used by that standby. According to the PostgreSQL 18 replication configuration reference, accessed September 17, 2026, synchronized_standby_slots is a primary-side list of physical replication slot names that logical WAL senders wait for before transmitting decoded changes. It is not interchangeable with synchronous_standby_names, which governs synchronous replication acknowledgements for transaction commit policy.

Evaluate the availability cost of waiting for a standby

When a slot named in synchronized_standby_slots does not exist or is invalidated, the PostgreSQL 18 replication configuration reference says logical replication will not proceed; the associated replication management functions can also block until the required physical slots confirm WAL receipt. That is deliberate ordering protection with an availability cost.

Proposed operating model: test that consequence. Temporarily make the required standby unavailable in nonproduction and verify which logical consumers stall, what alerts fire, how WAL retention changes, and who owns escalation. Do not make “remove the safety constraint” the automatic response to lag. The decision to trade failover protection for immediate logical throughput belongs to the incident commander and data owners under an explicit policy. For broader context on service responsibility, keep cloud database recovery and ownership boundaries separate from the upstream PostgreSQL behavior documented here.

Make readiness a fresh, complete evidence set

The PostgreSQL 18 failover procedure gives a readiness predicate for the required standby slot rows: the slot is synchronized, not temporary, and has no invalidation reason. The documentation additionally says all required slots must be present. That second clause is easy to lose when an operator runs a WHERE slot_name IN (...) query and only looks at the returned rows. If three rows return true but four slots were expected, the result is not “all healthy”; it is “one missing.”

The pg_replication_slots catalog reference, accessed September 17, 2026, defines the fields that make this predicate useful. temporary slots are not persisted to disk. synced identifies a logical slot synchronized from a primary; on a hot standby such slots cannot be used for decoding before promotion. invalidation_reason is null only when the slot is not invalidated. After promotion, the slot becomes part of the new primary’s state, but consumer continuity still depends on reconnection and downstream behavior.

Proposed acceptance rule: add set completeness and evidence freshness to the documented predicate.

Expected slot

DB

Observed

synced

temporary

invalidation

Captured

Reviewer

Decision

sub_orders

orders_prod

yes

true

false

null

T0

DBA-A

ready

cdc_billing

orders_prod

yes

true

false

null

T0

DBA-A

ready

cdc_search

orders_prod

no

not observed

not observed

not observed

T0

DBA-A

hold

A read-only standby query can capture the relevant fields:

SELECT slot_name,
       database,
       slot_type,
       synced,
       temporary,
       restart_lsn,
       confirmed_flush_lsn,
       wal_status,
       safe_wal_size,
       invalidation_reason,
       inactive_since
FROM pg_replication_slots
ORDER BY slot_name;

Do not reinterpret confirmed_flush_lsn as “the business side effect completed.” The pg_replication_slots catalog reference defines it as the address up to which a logical slot’s consumer has confirmed receiving data. That says nothing about a Kafka consumer committing a transaction, a warehouse merge finishing, an email being sent, or a search index reflecting the event. restart_lsn is different again: it is the oldest WAL address still potentially required by the slot.

Freshness also needs policy. Define a maximum evidence age appropriate to the change window and recapture immediately before the cutover decision. A screenshot or query result from yesterday can prove historical configuration; it cannot prove that an asynchronous synchronization process is ready now. A stale snapshot is therefore a separate hold condition even if every recorded row was true.

Observe WAL retention and invalidation before the drill

Logical slots retain resources. The pg_replication_slots catalog reference defines restart_lsn as the oldest WAL that might still be required by the slot and wal_status as the availability state of claimed WAL. reserved and extended still retain needed WAL; unreserved means the slot no longer retains all required files and some may be removed at the next checkpoint; lost means the slot is no longer usable. invalidation_reason can identify causes including removed WAL, removed required rows, insufficient wal_level, or idle timeout.

safe_wal_size requires context. The pg_replication_slots catalog reference defines it as the number of additional WAL bytes that can be written before the slot risks becoming lost, but PostgreSQL returns null both for lost slots and when max_slot_wal_keep_size = -1. Null is therefore not an unconditional healthy value; inspect wal_status, invalidation, and configuration together.

The PostgreSQL 18 replication configuration reference, accessed September 17, 2026, sets the documented default for max_replication_slots to 10 and max_slot_wal_keep_size to -1, the latter permitting unlimited slot-related WAL retention. Those are software defaults, not sizing recommendations for a CDC estate.

Signal

Interpretation

Proposed action

wal_status = lost

slot unusable

recover, do not promote for that consumer

non-null invalidation_reason

slot invalidated

hold/recover based on cause

wal_status = unreserved

WAL at removal risk

hold and investigate retention

small positive safe_wal_size

finite remaining margin

compare with measured WAL rate and drill duration

null safe_wal_size, max keep -1

unlimited slot cap configured

monitor filesystem capacity instead

growing restart gap

consumer/slot lag retaining WAL

owner investigates before cutover

Estimate retention from measurements, not invented throughput. Record WAL generation over representative intervals, the gap between current WAL and each slot’s restart_lsn, free space on the WAL filesystem, archive health, and the longest expected recovery or consumer outage. The database owner should define alerts that trigger before disk pressure turns a CDC problem into a primary availability problem.

Stop condition: missing required WAL, a lost or invalidated required slot, unexplained retention acceleration, or insufficient disk headroom to complete the planned window. Promotion may still be necessary during a real infrastructure emergency, but that becomes a recover path with acknowledged consumer risk, not a “ready” result.

Prepare fencing, endpoints and consumer ownership

Logical continuity can fail even when the slot is perfect if the old primary remains reachable. The PostgreSQL slot-synchronization guidance recommends disabling subscriptions before promotion, changing the subscription connection to the new primary, then re-enabling. It explicitly warns that if the old primary remains up, subscribers can continue receiving from it after promotion until the connection string changes, creating inconsistency.

That guidance is for PostgreSQL subscriptions. External connectors need their own pause, endpoint-change, credential, and restart procedure. Treat connector-specific behavior as deployment evidence, not something inferred from upstream PostgreSQL documentation.

Preparation item

Owner

Evidence

Stop condition

Old-primary fencing method

platform/commander

rehearsed command or control-plane action

cannot prevent writes/reconnects

Writer endpoint identity

platform

DNS/service target before and after

ambiguous target

PostgreSQL subscription control

DBA/subscriber owner

disable/connection/enable privileges

insufficient privileges

External connector control

CDC owner

pause/repoint/resume procedure

owner absent or procedure untested

Credentials

service owner

secret reference, not secret value

unavailable at cutover

Rollback/rebuild path

DBA + data owner

authoritative-source plan

no safe divergence recovery

Keep the runbook and its configuration assertions under version-controlled database operations. The change record should point to secret references but never store passwords, tokens, full connection strings with credentials, or private keys in evidence bundles.

A physical standby that has been promoted and accepted divergent writes is not simply “the standby again” if the former primary later returns. The PostgreSQL 18 physical failover documentation, accessed September 17, 2026, requires a mechanism to ensure the old primary knows it is no longer primary and describes rebuilding or re-establishing a standby after failover. Rejoining therefore requires an approved HA recovery method and an authoritative timeline. The exact tooling depends on deployment architecture, so this runbook does not prescribe an upstream-only command as a universal provider procedure.

Proposed operating model: assign one promotion commander, one database operator, one platform/fencing operator, and one owner per logical consumer cohort. Separate roles reduce the chance that a single operator both causes the topology change and declares downstream correctness without independent review.

Run a controlled promotion with an auditable event ledger

Use a synthetic fixture whose expected outcome is known independently of replication. The fixture should carry stable business identifiers such as event_id and order_id, plus a small set of state transitions that the downstream system can expose. Do not use wall-clock ordering alone as proof: clocks can differ, queues can reorder observation time, and downstream processing can be asynchronous.

A useful synthetic sequence is: one event committed well before the cutover barrier, one immediately before the controlled write stop, one after the new primary is established, and one event deliberately replayed at the consumer boundary during a failure injection. The test harness records which event IDs it created and what business state each should produce. This is expected test design, not a claim that the drill was executed.

Step

Evidence captured

Owner

Stop condition

Establish fixture

expected event IDs and target states

test owner

expected set uncertain

Capture slot inventory

complete expected-versus-observed snapshot

DBA

missing/not-ready/stale slot

Quiesce or bound writes

cutover barrier and acknowledged-write policy

commander/app owner

durability barrier unknown

Pause consumers

PostgreSQL subscriptions/external connectors paused as designed

CDC owners

old source can still feed consumer

Fence old primary

writer path disabled

platform

divergent writes possible

Promote designated standby

HA control-plane evidence

DBA/platform

wrong node or recovery state unclear

Repoint consumers

endpoint/connection evidence

CDC owners

any consumer points to old primary

Resume by cohort

consumer starts from intended slot

CDC owners

slot unusable or repeated fatal error

Reconcile ledger

expected IDs and business states matched

data/app owner

missing or unexplained duplicate effect

Follow the successful rehearsal path

Immediately before cutover, recapture the canonical expected set, subscriber discovery results, standby slot state, physical replication position, WAL-retention signals, and configuration revision. The PostgreSQL 18 failover procedure requires the needed slots to be present and ready on the standby before failover; synchronization itself is asynchronous.

For a planned promotion, stop or tightly bound new writes according to the organization’s durability policy, then prove that the designated standby has received/applied the required cutover state under the physical-replication design. Slot readiness does not prove that acknowledged transactions are durable on the standby. If the physical link is asynchronous, an unplanned primary loss can still lose acknowledged transactions that had not reached the standby; the runbook must state that risk rather than laundering it through a logical-slot check.

Disable PostgreSQL subscriptions according to the documented recommendation; pause external consumers using their approved procedure. Fence the old primary from application writes and, where possible, from consumer connections. Promote the designated standby through the deployment’s approved HA mechanism. The PostgreSQL 18 physical failover documentation describes pg_ctl promote and pg_promote() for triggering promotion of a log-shipping standby, while failure detection, fencing and provider control planes remain deployment-specific.

After promotion, verify the expected logical slots exist and are usable on the new primary. For PostgreSQL subscribers, alter the subscription connection to the new primary and re-enable only after the connection target is proven. The ALTER SUBSCRIPTION documentation covers ALTER SUBSCRIPTION ... CONNECTION, ENABLE, and DISABLE for these controls. External connectors should be repointed or allowed to follow a tested writer endpoint only when the owner has evidence that the endpoint now resolves to the promoted primary.

Resume one consumer cohort, generate the post-promotion synthetic event, and compare downstream observations with the independent expected-event ledger. Expected success is not “the slot advanced.” It is: all expected pre-cutover and post-cutover event IDs are accounted for; any repeated transport is handled according to the consumer contract; and the accepted business state matches the fixture.

Inject missing-slot, replay and retention failures

The rehearsal should also fail on purpose.

1.     Remove one expected slot from the audit input or test against a standby where it is absent; the left join must show MISSING, and approval must stop.

2.     Present an old readiness snapshot after changing the environment; the freshness gate must reject it.

3.     Stop synchronization for the physical standby used in synchronized_standby_slots; observe the documented effect on logical progress described in the PostgreSQL 18 replication configuration reference and confirm alerting and escalation.

4.     Crash or restart a logical consumer in a way that causes repeated delivery; verify that transport duplicates do not create unbounded duplicate business effects. The PostgreSQL logical decoding documentation explains that crash recovery can resend recent changes.

5.     Exercise a bounded retention-pressure scenario without exhausting production storage; verify that wal_status, safe_wal_size, disk alerts, and the hold path are understood.

If a required slot is missing after promotion, do not silently create a new one and declare continuity restored. Recovery depends on whether the needed history is still obtainable and on the connector’s bootstrap semantics. Preserve evidence first, then choose reconnect, repair, or rebootstrap.

Reconcile downstream effects, not just replication positions

Database positions are necessary but not sufficient. The pg_replication_slots catalog reference defines confirmed_flush_lsn as the position the logical slot’s consumer has confirmed receiving; it is not evidence that the next system in the chain committed its own transaction or that an external effect occurred exactly once. restart_lsn describes the oldest WAL that might still be required. Neither field proves semantic completeness in a downstream business model.

Reconciliation should therefore use stable identifiers and a bounded interval around the cutover. The event ledger should know which source events were expected, which state transitions they imply, and which consumer-specific evidence counts as accepted. For a warehouse that may be a durable row keyed by event_id; for a queue it may be a committed offset plus an idempotent sink record; for an application it may be a durable domain-state transition. These are consumer contracts, not PostgreSQL server guarantees.

Observation

Interpretation

Decision

Same event delivered twice, one business effect

transport replay safely deduplicated

acceptable if contract allows

Same event creates two charges/messages

duplicate business effect

recover

Event absent but later correction exists

investigate domain semantics

do not classify by count alone

Expected event absent everywhere downstream

probable gap

recover/hold

Row counts equal, IDs differ

semantic mismatch

recover

Schema apply error blocks subscriber

target schema incompatible

hold/recover

The PostgreSQL 18 logical replication restrictions, accessed September 17, 2026, state that logical replication does not replicate DDL or schema changes, and sequence state is not replicated. A subscriber can therefore have correct replicated rows while still being unsuitable for independent writes or promotion without separate schema and sequence management.

That boundary matters during incident response. Do not compare only total row counts and call the systems equal. A duplicate and a missing row can cancel numerically. Compare the stable event IDs, expected transitions, relevant keys, and accepted final state over a defined interval. Where the consumer transforms or filters data, reconcile the transformed contract rather than demanding physical equality with the publisher.

The same principle applies to corrections. A legitimate compensating event after failover is not necessarily a replication duplicate. Keep transport identity, business identity, and final business state as separate fields in the ledger so the incident team can explain why a repeated message did or did not matter.

Recover without erasing the failure evidence

Recovery begins by preserving what failed. Before recreating a slot, resetting a connector, skipping a transaction, resnapshotting a target, or rewinding/rebuilding a node, capture the expected inventory revision, observed pg_replication_slots rows, subscription state, endpoint target, relevant logs, physical-replication positions, connector offsets, and downstream mismatch sample. Store references to secrets, never the secrets themselves.

A replication slot does not contain a copy of the downstream database. Recreating a missing or invalidated slot at a new position does not automatically reconstruct history that has already become unavailable. The pg_replication_slots catalog reference explicitly marks lost slots unusable, and synchronization can refuse to persist a slot when required WAL or catalog rows are no longer available on the standby.

Failure state

Preferred decision

Conditional recovery path

Standby slot missing before planned cutover

hold

restore sync prerequisites; wait for valid synchronized slot; recapture evidence

Slot invalidated/lost

recover

connector-specific rebootstrap from retained source/snapshot; reconcile gap

Endpoint still reaches old primary

recover

stop consumer, fence old source, establish authority, assess divergence

Repeated delivery only

reconnect/repair

apply tested idempotency or dedupe contract; reconcile effects

Subscriber schema mismatch

repair

align schema under change control; resume and reconcile

Consumer position unknown

hold/recover

prove restart point or rebuild; never guess

Physical acknowledged-write loss suspected

escalate

authoritative source and business reconciliation, not slot repair alone

For PostgreSQL subscriptions, the ALTER SUBSCRIPTION documentation defines the ownership and privilege conditions for changing connection details, enabling or disabling a subscription, and altering subscription properties. A runbook that assumes emergency operators have those privileges but has never tested them has an access-control gap. That is why database performance and security fundamentals belong in the operational foundation: recovery depends on disciplined privileges as much as on replication syntax.

Do not destroy the original evidence in the act of recovery. If a rebootstrap succeeds, retain the reason it was required, the interval potentially affected, the source used to rebuild, and the post-recovery reconciliation result. “Green now” is not a substitute for explaining whether any business effect was lost, repeated, or corrected.

Roll out by consumer cohort with explicit stop rules

A single rehearsal is evidence for the topology and versions tested, not a permanent certification. Rollout should move from nonproduction rehearsal to a deliberately limited consumer cohort and only then to broader use. The cohort boundary should reflect consumer semantics and blast radius: for example, a replay-tolerant analytical sink should not be treated as equivalent to a payment-side effect processor.

Gate

Proceed when

Hold when

Nonproduction rehearsal

success and injected failures behave as expected

missing stop condition or owner

Limited cohort

slot, endpoint, replay and reconciliation evidence complete

unknown connector behavior

Broader rollout

prior cohort stable; no unresolved exceptions

provider support unknown

Topology change

runbook revalidated

standby/endpoint identity changed without test

PostgreSQL/connector upgrade

compatibility retested

version behavior assumed

No universal waiting period is proposed here. Teams should choose observation windows based on transaction volume, consumer latency, business criticality, and the time needed to expose delayed failures. What matters is that the duration is explicit before the change rather than shortened after a partial success.

Reassess the contract whenever the designated standby changes, a new publisher database appears, a connector changes slot management, subscriptions are added, failover properties change, or the management layer is upgraded. PostgreSQL’s server behavior is only one layer; managed-service restrictions and connector-specific recovery remain deployment checks.

Hard hold gates: a required consumer has no owner; provider support for the required failover behavior is unverified; the expected slot inventory cannot be independently reproduced; a required slot is missing or invalid; consumer duplicate handling is unknown; or downstream reconciliation cannot be run. In an emergency, commanders may still promote to restore the database service, but the decision must be recorded as recover, with explicit downstream risk, rather than retroactively labeled ready.

Package the evidence and divide ongoing ownership

The closeout record should allow a reviewer who was not on the call to reconstruct the decision. Capture what topology was intended, which exact slot set was expected, what the standby showed, which physical durability condition was used, how endpoints changed, which consumers reconnected, and how downstream correctness was reconciled. Keep timestamps, but do not treat timestamp ordering across systems as proof of causality.

Evidence item

Minimum retained content

Primary owner

Topology revision

cluster IDs, designated standby, endpoint identity

platform

Expected set

consumer, DB, slot, owner, failover requirement

CDC/data platform

Observed slot state

readiness fields + capture time

DBA

Config proof

relevant setting values, revision, redacted secrets

DBA/platform

Promotion ledger

commands/control-plane actions and approvals

incident commander

Endpoint proof

old source fenced; new source selected

platform

Consumer restart

start result, restart position/evidence

CDC owner

Reconciliation

expected IDs, duplicates, gaps, corrections

data/app owner

Residual exception

risk, owner, remediation date

commander/service owner

A practical evidence-retention checklist is compact: keep machine-readable query output where possible; store the reviewed expected-set revision; preserve logs around synchronization and promotion; retain configuration diffs; record consumer restart evidence; and retain the reconciliation result. Redact or omit passwords, tokens, private keys, raw secret-bearing connection strings, and unnecessary customer data.

Responsibility should match system boundaries. The DBA owns PostgreSQL configuration, slot state, WAL retention, and physical-replication evidence. Platform engineering owns fencing, endpoint routing, infrastructure automation, and provider control-plane behavior. CDC/data engineering owns connector restart semantics, offsets, dedupe behavior, and target reconciliation. Application/domain owners define what a correct business effect means. Incident command owns the final risk decision. That division aligns with the practical distinction discussed in DBA and data-engineering ownership, while the technical authority for PostgreSQL behavior remains upstream documentation.

The closeout should state one of three outcomes plainly. Proceed means the expected set is complete and fresh, required slots are ready, physical durability assumptions are satisfied for the planned procedure, endpoints/fencing are controlled, and downstream reconciliation passed. Hold means the change has not happened and evidence is missing or unsafe. Recover means promotion happened or a failure was exposed, and consumer correctness now requires repair, rebootstrap, or business reconciliation.

Build the database foundations behind this exercise

This failover drill sits on ordinary database disciplines: knowing what data must be durable, understanding recovery boundaries, querying system catalogs safely, monitoring resource pressure, and controlling privileged changes. Those foundations are broader than PostgreSQL failover slots, but without them the specialized runbook becomes a collection of commands without an evidence model.

Foundation

Application in this runbook

Backup and recovery

distinguish physical recovery from logical consumer rebuild

SQL and catalog reading

build expected-versus-observed slot audits

Monitoring

detect lag, WAL pressure, invalidation and stale evidence

Access control

ensure promotion and subscription changes use approved privileges

Disaster recovery

define fencing, authority, rollback and reconciliation

Change management

version the runbook and topology assumptions

The verified Refonte Learning program page, accessed September 17, 2026, lists a three-month program at 12–14 hours per week and explicitly covers database design, SQL optimization, backup and recovery, performance tuning, security, cloud database management, migration, disaster recovery, role-based access control, and monitoring; its FAQ names MySQL Workbench, Oracle SQL Developer and AWS RDS. The page does not establish PostgreSQL 18 failover-slot labs or CDC connector certification.

For readers building those broader foundations, the Refonte Learning Database Administrator Program is one relevant starting point; treat the PostgreSQL 18 failover exercise in this article as an independent advanced application, not as a promised syllabus module.

Answer the final proceed, hold or recover questions

Is a synced slot enough? No. The PostgreSQL 18 failover procedure requires the needed slots to be present and ready, and readiness for the standby row includes synchronized, persistent rather than temporary, and not invalidated. This runbook adds two proposed controls: independently prove that the expected set is complete, and require fresh evidence.

What does a missing result row mean? It means the health query has no evidence for that expected slot. It does not mean the slot is healthy. A left join or explicit set difference should make missing expected rows visible. The operational decision is hold before a planned cutover, or recover if promotion has already happened.

Can a crash repeat changes? Yes. The PostgreSQL logical decoding documentation explains that logical decoding can resend recent changes after a crash because slot position persistence occurs at checkpoints. The consumer must tolerate or correctly reconcile repeats. Do not promise exactly-once external effects from PostgreSQL slot state.

Does promotion prove no acknowledged-write loss? No. Logical-slot readiness addresses the ability to resume logical replication from the promoted server. Acknowledged-write durability depends on the physical replication and commit policy actually in force at the cutover. A planned failover can establish a controlled durability barrier; an unplanned loss of an asynchronously replicated primary can have a different recovery point.

Final gate

Proceed

Hold

Recover

Expected slot set

complete

unknown/missing

missing after promotion

Standby readiness

all required rows ready and fresh

stale/not-ready

slot lost/invalidated

WAL retention

adequate measured margin

pressure unexplained

needed history unavailable

Physical durability

planned barrier satisfied

unknown

suspected acknowledged-write loss

Fencing/endpoints

old source fenced; new target proven

ambiguous

divergence detected

Consumer replay

contract tested

unknown

harmful duplicate effect

Reconciliation

expected business states accounted for

not yet run

gap/mismatch found

The strongest decision is sometimes hold. Promotion is an availability action; logical-consumer continuity is a separate evidence problem. Approve the planned cutover only when the complete expected inventory, synchronized standby state, physical durability assumptions, reconnection path, and downstream reconciliation all agree. Anything less is not proof; it is an unverified assumption waiting to become an incident.