JusDB
Free DB Audit
High Availability

repmgr in 2026: Setup, Failover, and When to Move to Patroni

Set up repmgr 5.5 for PostgreSQL, configure repmgrd failover with a witness and fencing, run switchovers, and decide when Patroni is the better fit and how to migrate.

JusDB Team
Published November 6, 2026
19 min read

repmgr still runs many PostgreSQL streaming replication clusters, and it is still maintained: EDB published repmgr 5.5.1 on 5 November 2026 with a security fix. The questions that bring people to it are practical. How do you set up a primary, a standby, and a witness? What does repmgrd do when the primary stops answering? Why does repmgr cluster show print ! running as primary after a failover? This guide covers setup, automatic failover, fencing, switchover, and monitoring, then when Patroni, which uses a distributed configuration store (DCS) for consensus, is the better choice and how to move to it.

TL;DR
  • repmgr 5.5.1 is current. Its source compatibility matrix lists PostgreSQL 13 to 18, and every node must run the same repmgr major version.
  • With failover=automatic, repmgrd retries the primary 6 times, 10 seconds apart by default, then promotes the visible standby with the highest received LSN.
  • repmgr has no DCS and does not stop the old primary. A witness and location reduce false promotions; fencing is a script you write.
  • 5.5.1 shell-quotes %d, %c, and %a in notification commands; remove your own quotes when you upgrade.
  • Choose Patroni when the old primary must demote itself on a partition, or you need Kubernetes or load balancer health checks.

Scope and review date: November 2026. This post covers repmgr 5.5 with PostgreSQL 13 to 18 on Linux, and Patroni 4.1 for the comparison. Commands, defaults, and version numbers were checked against the repmgr and Patroni documentation and source on 9 November 2026. They were not run in a lab, so rehearse them on staging.


Is repmgr still maintained, and which PostgreSQL versions does it support?

Yes. The repmgr repository is maintained by EDB under the GPL v3 and is not archived. Releases are infrequent: 5.4.1 in April 2023, 5.5.0 in November 2024, and 5.5.1 on 5 November 2026, which adds packages for Debian 13 and RHEL 10 and escapes values substituted into notification commands.

The README and the compatibility matrix in the source tree say 5.5 supports PostgreSQL 13 to 18. The hosted installation requirements page still shows the 5.5.0 matrix (13 to 17) as of this review. PostgreSQL 13 reached end of life on 13 November 2025 and 14 follows on 12 November 2026, so in practice you run repmgr on 15 to 18.

bash
# On every node: binary version and the extension version in the repmgr database
repmgr --version
psql -d repmgr -Atc "SELECT extversion FROM pg_extension WHERE extname = 'repmgr';"

Interpretation: every node should report repmgr 5.5.x; the documentation warns that mixed major versions can stop repmgrd or break the cluster. As of 9 November 2026, the PostgreSQL community APT repository still ships 5.5.0 packages such as postgresql-18-repmgr, so check your repository before planning 5.5.1.

repmgr is a command line tool (clone, register, promote, follow, switchover, rejoin), the repmgrd daemon on each node, and a repmgr metadata schema replicated like any other data. There is no external consensus store: each repmgrd decides from what it can see. That keeps the footprint small, and it is the source of every split-brain question below.

What goes in repmgr.conf, and which PostgreSQL settings does repmgr need?

Start with PostgreSQL. The repmgr quick-start guide lists these settings; a clone needs two free WAL senders, and preloading the library takes a restart.

ini
# postgresql.conf on every node (or an included file)
wal_level = 'replica'
max_wal_senders = 10
max_replication_slots = 10      # only used if use_replication_slots=true
hot_standby = on
wal_log_hints = on              # lets pg_rewind work without data checksums
archive_mode = on
archive_command = '/bin/true'   # placeholder; point it at your archive
shared_preload_libraries = 'repmgr'

Interpretation: repmgr node rejoin --force-rewind uses pg_rewind, which needs wal_log_hints or data checksums enabled at initdb.

Then the node's own file. Four parameters are required: node_id (a unique integer above zero), node_name, conninfo (usable from every other node), and data_directory. Keep repmgr.conf outside the data directory, where a clone can overwrite it.

ini
# /etc/repmgr.conf on node1 (Debian/Ubuntu paths, PostgreSQL 18)
node_id=1
node_name='node1'
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/18/main'
pg_bindir='/usr/lib/postgresql/18/bin'
location='dc1'
priority=100
use_replication_slots=true

failover=automatic
promote_command='/usr/bin/repmgr standby promote -f /etc/repmgr.conf --log-to-file'
follow_command='/usr/bin/repmgr standby follow -f /etc/repmgr.conf --log-to-file --upstream-node-id=%n'

service_start_command='sudo pg_ctlcluster 18 main start'
service_stop_command='sudo pg_ctlcluster 18 main stop'
service_restart_command='sudo pg_ctlcluster 18 main restart'
service_reload_command='sudo pg_ctlcluster 18 main reload'
log_file='/var/log/postgresql/repmgrd.log'

Interpretation: failover defaults to manual, so nothing fails over until you set it. repmgr does not prepend pg_bindir to the promote, follow, or service commands, so give full paths. Without service commands it falls back to pg_ctl, which the documentation warns can confuse systemd; on Debian it recommends sudo pg_ctlcluster with a passwordless sudoers entry.

How do you register a primary and clone a standby?

Create a superuser and database for repmgr's metadata, allow it in pg_hba.conf for both normal and replication connections, then register the primary. The standby needs an empty data directory: repmgr refuses to clone into an existing instance, so if your packages created a default cluster, stop it and empty its data directory first.

bash
# On node1, as postgres
createuser -s repmgr
createdb repmgr -O repmgr
# pg_hba.conf: host replication repmgr 10.0.0.0/24 scram-sha-256
#              host repmgr      repmgr 10.0.0.0/24 scram-sha-256

Interpretation: the quick-start guide uses trust for brevity. In production, put the password in ~postgres/.pgpass on every node, because repmgrd connects without a prompt.

repmgr setup runbook: primary, standby, witness, repmgrd

Eight steps; step 2 is the only one that restarts the primary

  1. Install repmgr on every node

    The package must match the PostgreSQL major version.

    sudo apt install postgresql-18-repmgr
  2. Preload the repmgr library on the primary

    Restart

    Add shared_preload_libraries = 'repmgr' and the replication settings, then restart once.

    sudo pg_ctlcluster 18 main restart
  3. Register the primary

    This installs the repmgr extension and writes the first node record.

    repmgr -f /etc/repmgr.conf primary register
  4. Check the clone from the standby

    The dry run checks connectivity and that two WAL senders are free on the source.

    repmgr -h node1 -U repmgr -d repmgr \ -f /etc/repmgr.conf standby clone --dry-run
  5. Clone the standby and start it

    Add --copy-external-config-files if your config lives outside the data directory.

    repmgr -h node1 -U repmgr -d repmgr \ -f /etc/repmgr.conf standby clone -c sudo pg_ctlcluster 18 main start
  6. Register the standby

    Without a node record, a standby is never a promotion candidate.

    repmgr -f /etc/repmgr.conf standby register
  7. Register the witness

    Its own PostgreSQL instance and host, in the primary's location.

    repmgr -f /etc/repmgr.conf witness register -h node1
  8. Start repmgrd on every node

    On Debian, set REPMGRD_ENABLED=yes and REPMGRD_CONF in /etc/default/repmgrd first.

    sudo systemctl start repmgrd repmgr -f /etc/repmgr.conf service status

Main risk: until step 8, failover is manual. After it, a misconfigured promote_command or a missing witness is live, so test a failover on staging before step 8 in production.

Confirm on the primary that pg_stat_replication shows each standby with an application_name equal to its node_name; repmgr relies on that match to detect disconnections. The replication monitoring guide covers lag and slot queries.

How does repmgrd decide which standby to promote?

Each standby's repmgrd checks its upstream every monitor_interval_secs (default 2). When the check fails, it makes reconnect_attempts tries (default 6), reconnect_interval seconds apart (default 10), before it starts an election. The automatic failover chapter describes the safeguards; the election itself is in repmgrd-physical.c.

  • The candidate is the visible node with the highest last received LSN; ties go to the higher priority, then the lower node_id. Nodes with priority=0 or failover=manual never win.
  • The election is cancelled if the node sees no more than half of the nodes sharing the failed upstream (itself, sibling standbys, and the witness), or no node in the primary's location.

repmgrd automatic failover, start to finish

Follow the numbers; the witness only counts toward the visibility check in step 2

repmgrd automatic failover sequence Step 1: primary node1 stops answering and each standby's repmgrd retries it, 6 times 10 seconds apart by default. Step 2: the standbys elect a candidate by last received LSN, then priority; the witness counts toward the visibility majority. Step 3: node2 is promoted and node3 follows it. node1 is marked failed, not stopped. node1 primary, unreachable Election repmgrd on standbys node2 standby promote Witness counts as visible node3 standby follow 1 6 retries, 10 s apart 2 highest LSN, then priority 3 siblings follow node1 is marked failed, not stopped

What repmgr does not do: nothing in this sequence stops node1. If it was only cut off from the standbys, it can still accept writes until your fencing script acts.

Detection time comes from your settings. With the defaults, roughly a minute passes between the first failed check and the election; lower values promote faster and also during short network blips.

ini
# repmgr.conf failover tuning
reconnect_attempts=6
reconnect_interval=10
primary_visibility_consensus=true     # must match on all nodes
failover_validation_command='/usr/local/bin/repmgr-validate.sh %n %v %t'

Interpretation: primary_visibility_consensus cancels the failover if any standby or the witness saw the primary within the last two monitor intervals. A validation script that exits non-zero aborts the promotion and reruns the election after 15 seconds by default.

Delayed standbys

repmgrd ignores recovery_min_apply_delay when it picks a candidate. The repmgr FAQ recommends priority=0 for delayed standbys.

How do you prevent split-brain when repmgr has no DCS?

Split-brain needs two things: a standby that promotes while the old primary is still alive, and clients that keep writing to the old primary. repmgr gives you tools against the first. The second is yours to handle.

The witness node and locations

In a two-node cluster with no witness, the standby counts only itself, sees one of one node, and promotes on any network split. With a witness in the primary's data centre, a standby that sees neither the witness nor the primary sees one of two nodes, assumes a network problem, and enters degraded monitoring instead. The witness must never share a physical host with another node.

Across data centres, set location on every node: a standby promotes only if it can see at least one node in the failed primary's location.

Fencing the old primary

repmgr ships hooks, not a fencing mechanism. The reference PgBouncer fencing example wraps promote_command: it promotes the node, rewrites every PgBouncer's database section from repmgr.nodes, and reloads it, so writes stop reaching the old primary. The script must still call repmgr standby promote, or the metadata is not updated. The other hook runs on the old primary itself, when too few standbys remain attached.

ini
# repmgr.conf on every node (only acts while the node is primary)
child_nodes_check_interval=5
child_nodes_connected_min_count=1
child_nodes_connected_include_witness=true
child_nodes_disconnect_timeout=30
child_nodes_disconnect_command='/usr/local/bin/fence-self.sh %p'

Interpretation: a primary that loses all its standbys and the witness for 30 seconds runs the script once; it does not run while repmgrd is paused. A standby that fell back to archive recovery also counts as disconnected, so a fence that stops PostgreSQL can turn a replication hiccup into an outage. Prefer blocking client access, and test both cases.

How do you run a switchover, and bring a failed primary back?

A planned switchover runs on the standby you want to promote. Over passwordless SSH, it shuts down the primary cleanly, promotes the standby, and restarts the old primary as a standby, pausing repmgrd meanwhile.

bash
# On node2, the standby to promote. Check first, then run with full logging.
repmgr -f /etc/repmgr.conf node service --list-actions --action=stop
repmgr -f /etc/repmgr.conf standby switchover --siblings-follow --dry-run
repmgr -f /etc/repmgr.conf standby switchover --siblings-follow \
    --log-level=DEBUG --verbose 2>&1 | tee /tmp/switchover.log

Interpretation: the dry run checks SSH, lag, the archive backlog, and the stop command, but cannot prove a clean shutdown. If the shutdown runs past shutdown_check_timeout (default 60 seconds, set on the promotion candidate), the switchover aborts with shutdown of the primary server could not be confirmed. Block application writes first.

After an unplanned failover, the old primary has usually diverged. Rejoin it as a standby and let pg_rewind discard the transactions the new primary never received.

bash
# On node1, with PostgreSQL stopped. -d points at the new primary.
repmgr -f /etc/repmgr.conf node rejoin \
    -d 'host=node2 user=repmgr dbname=repmgr' \
    --force-rewind --config-files=postgresql.local.conf --dry-run

Interpretation: remove --dry-run once it passes. --config-files keeps data-directory config files that pg_rewind would overwrite. On PostgreSQL 13 and later, --force-rewind also recovers a node that did not shut down cleanly.

A running standby that has not diverged only needs repmgr standby follow --upstream-node-id=2, which on PostgreSQL 13 and later reloads instead of restarting. If it fails with timeline 2 forked off current database system timeline 1, the node has diverged and needs the rejoin above. For other maintenance, repmgr service pause stops every repmgrd from acting until repmgr service unpause.

How do you monitor a repmgr cluster?

repmgr cluster show polls every node from where you run it and compares the result with the metadata. ! means the real role differs from the metadata, ? means no connection, and - marks a node recorded as failed.

repmgr cluster show after an automatic failover

Illustrative output shaped like repmgr 5.5 --compact output; node names are examples

postgres@node3:~
$ repmgr -f /etc/repmgr.conf cluster show --compact ID | Name | Role | Status | Upstream | Location | Prio. | TLI----+-------+---------+-----------+----------+----------+-------+----- 1 | node1 | primary | - failed | | dc1 | 100 | 2 | node2 | primary | * running | | dc1 | 100 | 2 3 | node3 | standby | running | node2 | dc1 | 100 | 2 4 | node4 | witness | * running | node2 | dc1 | 0 | n/a

Exit code 25 is the alert: cluster show returns ERR_NODE_STATUS (25) when a node is not in its expected state. The column layout and markers follow the cluster show reference.

For alerting, use the machine-readable forms and the event log rather than parsing the table.

bash
# node ID, availability (0 up, -1 down), recovery (0 primary, 1 standby)
repmgr -f /etc/repmgr.conf cluster show --csv
# Nagios-style checks: role, lag, archive backlog, slots; then the daemon
repmgr -f /etc/repmgr.conf node check --nagios
repmgr -f /etc/repmgr.conf node check --repmgrd
# What happened during the last failover, newest first
repmgr -f /etc/repmgr.conf cluster event --limit=20

Interpretation: after a failover, expect repmgrd_failover_promote on the new primary and repmgrd_failover_follow on each sibling; a missing follow event points at a stranded standby. node check --repmgrd returns WARNING when the daemon is paused, which catches a forgotten unpause.

To push events instead, set event_notification_command. This is where 5.5.1 changes behavior.

ini
# repmgr 5.5.0 and earlier: quote %t and %d yourself
event_notification_command='/usr/local/bin/repmgr-notify.sh %n %e %s "%t" "%d"'

# repmgr 5.5.1: %d, %c and %a arrive already shell-quoted; quote only %t
event_notification_command='/usr/local/bin/repmgr-notify.sh %n %e %s "%t" %d'

Interpretation: the 5.5.1 release escapes node metadata substituted into event_notification_command and failover_validation_command. Keep your own quotes and the literal quote characters reach your script, so change the command in the same change as the package upgrade.

When is Patroni the better choice than repmgr?

The core difference is who holds the truth about the primary. In repmgr, each standby decides from what it can reach. In Patroni, a node may run as primary only while it holds a leader lock in the DCS, and the Patroni documentation says a primary that cannot update the lock is demoted before the lock expires.

repmgr 5.5 and Patroni 4.1 side by side

Switch tools to compare how each one handles the same failure

repmgr 5.5

Arearepmgr 5.5
Who picks the new primaryEach standby's repmgrd, by received LSN and priority
Extra infrastructureNone; an optional witness PostgreSQL instance
Old primary during a partitionKeeps running as primary unless your scripts fence it
Default failure detectionreconnect_attempts=6, reconnect_interval=10
Client routingYour own: promote script, PgBouncer reload, DNS, or a virtual IP
KubernetesNo built-in support

Patroni 4.1

AreaPatroni 4.1
Who picks the new primaryThe member that takes the DCS leader lock, within maximum_lag_on_failover
Extra infrastructureA DCS: etcd, Consul, or ZooKeeper (3 or 5 nodes), or the Kubernetes API
Old primary during a partitionDemotes itself when it cannot renew the lock; an optional watchdog resets the host
Default failure detectionttl=30, loop_wait=10, retry_timeout=10
Client routingREST health checks (/primary, /replica) for HAProxy or a load balancer
KubernetesCan store the leader key in Kubernetes objects, with no separate etcd

The deciding row: what the old primary does during a partition. If your fencing has never been tested, that row is the strongest reason to move.

repmgr stays reasonable when the cluster is small and stable, the team knows it, Kubernetes is not in the plan, and fencing (PgBouncer, a virtual IP with STONITH, or a cloud API call) has passed a failover drill. It also spares you running a DCS.

Patroni fits better when standbys span sites where partitions are realistic, when the old primary must stop taking writes without a custom script, on Kubernetes, when HAProxy or a load balancer should follow the leader through HTTP checks, or when you want quorum-based synchronous replication, added in Patroni 4.0. The cost is the DCS: it must itself be highly available, and an unstable DCS can demote a healthy primary. failsafe_mode keeps a primary running through a DCS outage only if every known member confirms it over the REST API.

As of November 2026, Patroni's current releases are 4.1.5 and 4.0.11 (12 August 2026). Our Patroni with Consul guide covers the DCS side if etcd is not already in your estate.

How do you migrate from repmgr to Patroni?

You do not need to re-clone the standbys. Patroni's Convert a Standalone to a Patroni Cluster procedure starts Patroni on each existing node, primary first, and Patroni takes over the running PostgreSQL. The repmgr-specific steps are our reading of both tools' documentation, not a vendor procedure, so rehearse them. Build the DCS first, then stop repmgrd everywhere: two failover managers will fight.

bash
# 1. Stop repmgr's failover manager on every node (Debian unit name)
repmgr -f /etc/repmgr.conf service pause
sudo systemctl disable --now repmgrd
# 2. List the physical slots repmgr created
psql -Atc "SELECT slot_name, active, restart_lsn FROM pg_replication_slots;"

Interpretation: repmgr names its slots repmgr_slot_1, repmgr_slot_2, and so on. Patroni drops unknown slots when use_slots is on, so declare them as permanent slots. Then disable the PostgreSQL systemd unit and start Patroni, primary first.

yaml
# Fragment of patroni.yml on the primary during the takeover
bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_slots: true
      use_pg_rewind: true
    slots:
      repmgr_slot_2:
        type: physical
      repmgr_slot_3:
        type: physical

Interpretation: Patroni writes bootstrap.dcs to the DCS once, when it first initializes the cluster; later file edits have no effect, so confirm the slots arrived with patronictl show-config and change settings with patronictl edit-config. Keep loop_wait + 2 * retry_timeout <= ttl.

bash
# 3. Hand PostgreSQL's start-up to Patroni
patronictl -c /etc/patroni/patroni.yml restart pgcluster node2
patronictl -c /etc/patroni/patroni.yml restart pgcluster node3
patronictl -c /etc/patroni/patroni.yml restart pgcluster node1   # in the window

# 4. Once Patroni's slots have caught up, drop the permanent ones
patronictl -c /etc/patroni/patroni.yml edit-config pgcluster

Interpretation: remove a permanent slot only when Patroni's slot for that member has a restart_lsn at least as far ahead. Patroni also strips recovery parameters, such as the primary_conninfo repmgr wrote, from postgresql.auto.conf.

Clean up last: take repmgr out of shared_preload_libraries (another restart), drop the repmgr database, remove the packages, and repoint monitoring to patronictl list or the REST API. The standalone to Patroni walkthrough shows a full Patroni configuration.

The takeover is not a failover test

Run a patronictl switchover and a forced failover on staging, and confirm your load balancer follows the leader, before you call the migration done.

Frequently asked questions

Is repmgr still maintained in 2026?

Yes. EDB maintains repmgr, and the repository is not archived. repmgr 5.5.1 was published on 5 November 2026 with a security fix for notification commands and packages for Debian 13 and RHEL 10. Releases are infrequent: the previous one, 5.5.0, came out in November 2024.

Does repmgr prevent split-brain?

Not on its own. repmgrd cancels a failover when it cannot see more than half of the nodes that share the failed primary, and a witness node and location settings reduce false promotions. repmgr does not stop the old primary, though. You need a tested fencing script, for example one that reconfigures PgBouncer or blocks clients.

What is the main difference between repmgr and Patroni?

Patroni uses a distributed configuration store such as etcd, Consul, ZooKeeper, or the Kubernetes API to hold a leader lock, and a primary that cannot renew the lock demotes itself. repmgr has no consensus store: each standby's repmgrd decides from what it can reach, and fencing the old primary is left to your scripts. repmgr needs less infrastructure; Patroni handles partitions with less custom code.

Can I migrate from repmgr to Patroni without re-cloning standbys?

Yes. Patroni's documented procedure for existing clusters starts Patroni on each running node, primary first, and Patroni takes over the running PostgreSQL. Stop repmgrd everywhere first, keep repmgr's replication slots as permanent slots until Patroni's slots catch up, and rehearse on a staging copy.

Key takeaways

  • repmgr 5.5.1 (5 November 2026) is current and EDB-maintained; run the same repmgr major version on every node.
  • Set failover=automatic, full-path promote_command and follow_command, and service commands, and add a witness to any two-node cluster.
  • repmgrd never stops the old primary; fence it from promote_command or child_nodes_disconnect_command, and test the fence.
  • On upgrading to 5.5.1, remove your own quotes around %d, %c, and %a in notification commands.
  • Move to Patroni when partitions, Kubernetes, or load balancer health checks matter more than avoiding a DCS; the takeover keeps existing standbys.

Review or replace repmgr with JusDB

JusDB's PostgreSQL high availability team can review an existing repmgr cluster's configuration, witness placement, and fencing, run a failover drill on staging, or plan and run a move to Patroni with a rehearsed rollback path. Our repmgr reference and Patroni reference pages cover the architecture of each.

Bring your topology, repmgr and PostgreSQL versions, repmgr.conf files, and how clients find the primary today. Your team approves every production change.

Share this article

Database engineering notes

Articles like this one, in your inbox. No spam, unsubscribe anytime.

JusDB Team

Official JusDB content team

Keep reading

MySQL Group Replication (2026): Multi-Primary HA, Conflict Resolution & Production Setup

Production-ready MySQL Group Replication deployment guide. Learn cluster sizing, monitoring setup, performance tuning, and disaster recovery planning.

MySQL5 minMay 13, 2026
Read

MariaDB Galera Cluster Production Guide: Mariabackup, MaxScale & Schema Strategy

Production MariaDB Galera Cluster: mariabackup-based SST, MaxScale Galera-aware routing, schema-change strategy with TOI vs RSU, and a troubleshooting playbook for the failures that actually take down production.

MySQL17 minMay 3, 2026
Read

Patroni with Consul DCS: PostgreSQL HA Without etcd

Configure Patroni to use Consul instead of etcd as its DCS for PostgreSQL HA. Covers Consul setup, patroni.yml, service discovery, HAProxy routing, and failover testing.

PostgreSQL11 minMar 5, 2026
Read