Loading...

We've detected that your browser language is Chinese. Would you like to visit our Chinese website? [ Dismiss ]
By: Dylan

What is Patroni?

Patroni is an open-source Python-based framework for building highly available PostgreSQL clusters. It manages PostgreSQL instances and coordinates leader election through a distributed configuration store (DCS) such as etcd, Consul, ZooKeeper, or Kubernetes. Unlike manual replication setups, Patroni eliminates the risk of split-brain and ensures that only one primary node exists at any time. This makes it ideal for mission-critical applications requiring for 9.99% uptime.

In this Patroni PostgreSQL setup guide,  you will know how to build a Patroni PostgreSQL cluster with detailed steps.

i2Availability for Application-Level Disaster Recovery

Professional high-availability solution designed for critical workloads across physical, virtual, and hybrid environments. Automated failover, Near-zero RPO and RTO.

FREE Trial for 60-Day

Patroni PostgreSQL Architecture and Components

A typical Patroni PostgreSQL cluster consists of PostgreSQL, Patroni, a distributed configuration store (DCS), and usually a client connection layer to provide automated high availability. Each component has a different responsibility.

Patroni Architecture

  • DCS layer: A distributed store such as etcd, Consul, ZooKeeper, or Kubernetes, that stores cluster metadata, leader lease tokens, and configuration parameters. It enforces quorum to prevent split-brain scenarios during failover events.
  • Database layer: Each node runs both PostgreSQL and the Patroni agent. Patroni manages the local PostgreSQL service, configures streaming replication between primary and replicas, and communicates with the DCS to report node status.
  • Routing layer (HAProxy): An HAProxy or similar routing layer can provide a stable endpoint for applications and direct connections to the current primary.

Prerequisites for Patroni PostgreSQL Setup

Before beginning your setup, verify that your infrastructure, operating system, and network configuration meet requirements to support a stable, highly available cluster.

1. For database nodes, a minimum of 2 servers (1 primary + 1 standby), but 3 nodes are recommended for full redundancy during maintenance or unplanned outages.

2. For the distributed configuration store (DCS), a 3-node etcd cluster

3. For production environments, deploy etcd nodes on separate servers from PostgreSQL nodes.

4. Ensure all nodes have Python 3 and pip installed, as well as access to the official PostgreSQL PGDG repository for certified packages.

5. All cluster components must be able to communicate reliably. At minimum, plan connectivity for:

Component

Typical Port

Purpose

PostgreSQL

5432

Database connections and replication

Patroni

8008

Health checks and cluster management

etcd

2379/2380

Client and peer communication

Step-by-Step Patroni PostgreSQL Setup

This PostgreSQL Patroni tutorial will guide you on how to set up PostgreSQL high availability with Patroni, including package installation to running a multi-node cluster.

We use etcd as the DCS (the most common production choice) and Debian/Ubuntu as the base OS, with notes for cross-platform equivalents where applicable.

Step 1. Install PostgreSQL on All nodes

First, enable the official PostgreSQL PGDG repository to get latest packages:

bash
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh

Next, install your target PostgreSQL version.

bash
sudo apt install -y postgresql-16 postgresql-contrib-16

Once installed, stop the default PostgreSQL systemd service and disable it entirely. Patroni will start, stop, and configure PostgreSQL on its own schedule, so the OS-level service must not interfere:

bash
sudo systemctl stop postgresq
sudo systemctl disable postgresql

Finally, remove the default pre-created database cluster. Patroni will initialize a fresh cluster with its own configuration during bootstrap:

bash
sudo pg_dropcluster 16 main

This clean state ensures Patroni has full control over PostgreSQL configuration, data directories, and replication setup without conflicts from package defaults.

Step 2. Install Patroni on All Nodes

There are two primary installation methods: system packages (recommended for Debian/RHEL) and pip (for latest versions or custom setups).

Option 1 – Install via system package (Debian/Ubuntu):

The PGDG repository includes a maintained Patroni package. Install it with:

bash
sudo apt install -y patroni

Option 2 – Install via Pip (cross-platform)

For systems without official packages, or to use the latest Patroni release with etcd v3 support, install via pip:

bash
sudo apt install -y python3 python3-pip
sudo pip3 install patroni[etcd3]

Verify the installation with:

bash
patroni --version
Note: The [etcd3] extra ensures compatibility with the etcd v3 API, which uses a different protocol than the older etcd v2 default in Patroni. Always use etcd3 for modern etcd deployments.

Step 3. Configure etcd DCS Connection

You can add the etcd settings directly to your main Patroni YAML file. For a 3-node etcd cluster, the configuration block looks like this:

yaml
etcd3:
   hosts: 10.0.0.1:2379,10.0.0.2:2379,10.0.0.3:2379

Pay close attention to the etcd3 key name rather than plain etcd. Patroni defaults to the legacy etcd2 protocol for backward compatibility. Using etcd3 is required for etcd versions 3.0 and above, which are standard in all current production environments.

Step 4. Create the Patroni YAML Configuration File

YAMAL is critical for setup. It defines node identity, DCS connection, bootstrap behavior, PostgreSQL settings, and replication rules.

The following is a production-ready configuration, with explanations for each key component.

Global & Node Identity Settings

yaml
scope: postgres-cluster
namespace: /db/
name: pg-node1
  • scope: A unique name for this Patroni cluster. All nodes in the same cluster share the same scope.
  • namespace: The root path in the DCS where all cluster keys are stored. It allows one DCS to host multiple independent Patroni clusters.
  • name: A unique identifier for this specific node. Must be different on every server.

DCS Behavior Settings

yaml
bootstrap:esxcli storage filesystem list
  dcs:
    ttl: 30
   loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    primary_start_timeout: 300
    synchronous_mode: false
  • ttl: The lifetime of the leader lease in seconds. If the primary node fails to renew its lease within this window, a failover is triggered.
  • loop_wait: How often Patroni renews the leader lease and polls cluster state.
  • maximum_lag_on_failover: The maximum allowed replication lag (in bytes) for a replica to be eligible for promotion during failover. This prevents promoting a severely out-of-date node.
  • synchronous_mode: Set to true to enable synchronous replication for maximum data durability at the cost of write performance.

PostgreSQL Bootstrap Settings

Still under the bootstrap.dcs section, define PostgreSQL parameters and access controls that apply cluster-wide:

yaml
postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: on
        max_connections: 200
        shared_buffers: 2GB
        effective_cache_size: 6GB
      pg_hba:
       - host replication replicator 10.0.0.0/24 scram-sha-256
       - host all all 10.0.0.0/24 scram-sha-256
        - local all all peer
  • use_pg_rewind: Enables pg_rewind to resync old primary nodes after failover without rebuilding the entire data directory.
  • use_slots: Uses PostgreSQL replication slots to prevent WAL files from being removed before replicas have applied them.
  • pg_hba: Defines host-based authentication rules for replication and regular connections. Customize the CIDR ranges to match your internal network.

Local PostgreSQL Node Settings

The top-level postgresql section configures the local PostgreSQL instance on this specific node:

yaml
postgresql:
  listen: 0.0.0.0:5432
  connect_address: 10.0.0.11:5432
  data_dir: /var/lib/postgresql/16/main
  bin_dir: /usr/lib/postgresql/16/bin
  authentication:
    replication:
     username: replicator
      password: replicator_password
    superuser:
      username: postgres
      password: postgres_password
 create_replica_methods:
    - basebackup
  basebackup:
   max-rate: '100M'
  • listen: The address PostgreSQL binds to. Use 0.0.0.0 to allow external connections.
  • connect_address: The address other nodes use to connect to this instance for replication.
  • authentication: Credentials for replication and superuser access. Patroni will automatically create the replicator user during bootstrap.
Note: On Debian systems, you can alternatively use the pg_createconfig_patroni helper tool to generate a Debian-optimized configuration file automatically.

Step 5. Bootstrap the Patroni Cluster

With configuration in place, start the cluster one node at a time. The first node you start will initialize the cluster and become the initial primary (leader).

First, set correct permissions on the configuration and data directories:

bash
sudo mkdir -p /var/lib/postgresql/16/main
sudo chown -R postgres:postgres /var/lib/postgresql/16
sudo chown postgres:postgres /etc/patroni/patroni.yml

Enable and start the Patroni systemd service on the first node only:

bash
sudo systemctl daemon-reload
sudo systemctl enable patroni
sudo systemctl start patroni

Wait 30–60 seconds for the first node to bootstrap the cluster. Then start Patroni on the remaining replica nodes using the same commands. Each replica will automatically detect the existing primary via the DCS, run a basebackup to clone the data directory, and begin streaming replication

Tip: If you want a specific node to be the initial primary, simply start Patroni on that node first and wait for it to claim the leader lease before starting the others

Step 6. Verify Cluster Health

Once all nodes are running, verify the cluster status using the patronictl command-line utility. Run this from any node as the postgres user:

bash
patronictl -c /etc/patroni/patroni.yml list

A healthy cluster will show output similar to this:

plaintext
+ Cluster: postgres-cluster ----------+----+-----------+
| Member   | Host       | Role    | State     | Lag in MB |
+----------+------------+---------+-----------+-----------+
| pg-node1 | 10.0.0.11  | Leader  | running   |           |
| pg-node2 | 10.0.0.12  | Replica | streaming |       0.0 |
| pg-node3 | 10.0.0.13  | Replica | streaming |       0.0 |
+----------+------------+---------+-----------+-----------+

Confirm that:

  • One node has the Leader role and is in running state.
  • All other nodes have the Replica role and are in streaming state.
  • Replication lag is 0 or near 0 under normal load.

You can also verify direct PostgreSQL connectivity to confirm the database is accessible:

bash
psql -h 10.0.0.11 -p 5432 -U postgres -c "SELECT version();"

Basic Patroni PostgreSQL setup is complete. The next section will help you add a connection routing layer.

Add HAProxy for Connection Routing

The basic setup delivers automated failover and streaming replication; direct client connections require tracking which node is the current primary and manually updating connection strings after every role change.

And HAProxy can act as a rasparent routing layer that provides stable, fixed endpoints for applications, while automatically detecting node roles and health status via Patroni’s built-in REST API.

Below are the steps to add HAProxy for Connection Routing

1. Install HAProxy

On Debian/Ubuntu systems, install HAProxy from the official distribution repositories:

bash
sudo apt install haproxy -y

2. Configure HAProxy Backends

Edit the main configuration file at /etc/haproxy/haproxy.cfg to define two separate frontend-backend pairs: one for read-write primary traffic and one for read-only replica traffic.

cfg
global
    maxconn 4096

defaults
    mode tcp
    timeout connect 5s
    timeout client 30s
    timeout server 30s

# Read-write endpoint (routes exclusively to the current primary)
frontend postgres_frontend
    bind *:5000
   default_backend postgres_backend
backend postgres_backend
   option httpchk GET /primary
   http-check expect status 200
   default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
   server pg-node1 10.0.0.11:5432 check port 8008
    server pg-node2 10.0.0.12:5432 check port 8008
   server pg-node3 10.0.0.13:5432 check port 8008

# Read-only endpoint (load-balances across all replicas)
frontend postgres_replica_frontend
    bind *:5001
    default_backend postgres_replica_backend

backend postgres_replica_backend
    option httpchk GET /replica
    http-check expect status 200
    default-server inter 3s fall 3 rise 2
    server pg-node1 10.0.0.11:5432 check port 8008
   server pg-node2 10.0.0.12:5432 check port 8008
    server pg-node3 10.0.0.13:5432 check port 8008

# Optional stats dashboard
listen stats
    bind *:7000
   stats enable
    stats uri /

Key configuration notes:

  • The option httpchk GET /primary directive queries Patroni’s REST API on port 8008. A node only returns HTTP 200 to this endpoint if it is the active cluster leader, so HAProxy will never send write traffic to a replica.
  • The /replica endpoint returns 200 for any healthy standby node, enabling round-robin load balancing of read queries across all replicas.
  • The on-marked-down shutdown-sessions option gracefully terminates existing connections when a node is demoted from primary, preventing stale connections to the old leader during failover.

3. Test Connection Strings

    Restart HAProxy to apply the configuration:

    bash
    sudo systemctl restart haproxy

    Verify connectivity using standard PostgreSQL client tools. Connect to the read-write primary endpoint:

    bash
    psql -h haproxy-host -p 5000 -U postgres -d postgres

    Connect to the read-only replica endpoint for read-heavy workloads:

    bash
    psql -h haproxy-host -p 5001 -U postgres -d postgres

    With HAProxy deployed, your patroni postgresql cluster gains a production-ready access layer that fully decouples application connections from underlying node role changes and failover events.

    Manage Patroni PostgreSQL Cluster

    Unlike traditional PostgreSQL replication deployments that require manual edits on every node, Patroni centralizes all cluster state in the DCS, so changes propagate consistently and automatically across all nodes. Below are how to manage your cluster.

    1. Essential Patronictl Commands

    `patronictl` is the main interface for cluster operations, and it is invoked using the `-c` flag to point to the local configuration file.

    • View cluster health: Verify node roles, replication state, and lag — your primary diagnostic for cluster status:

    bash
    patronictl -c /etc/patroni/patroni.yml list

    • Planned switchover: Gracefully promote a replica to primary for scheduled maintenance with zero data loss:

    bash
    patronictl -c /etc/patroni/patroni.yml switchover --candidate pg-node2 

    • Manual failover: Force a promotion when the current leader is unresponsive and automatic failover has not triggered:

    bash
    patronictl -c /etc/patroni/patroni.yml failover --candidate pg-node3 --force 

    • Rolling restart: Apply configuration changes by restarting nodes sequentially with no cluster downtime:

    bash
    patronictl -c /etc/patroni/patroni.yml restart postgres-cluster 

    • Reinitialize a replica: Rebuild a corrupted or out-of-sync replica from the primary via basebackup:

    bash
    patronictl -c /etc/patroni/patroni.yml reinit postgres-cluster pg-node3 

    2. Dynamic Configuration Changes

    Cluster-wide PostgreSQL and Patroni settings are stored persistently in the DCS, overriding local defaults. Edit the full configuration interactively with:

    bash
    patronictl -c /etc/patroni/patroni.yml edit-config 

    You can also update individual parameters directly, for example raising connection limits:

    bash
    patronictl -c /etc/patroni/patroni.yml edit-config --set "postgresql.parameters.max_connections=300" 

    Changes apply to all nodes automatically. Parameters that require a PostgreSQL restart (such as wal_level or shared_buffers) can be rolled out via rolling restart to avoid downtime.

    3. Replication Modes

    By default, Patroni uses asynchronous streaming replication, which optimizes for write throughput and low latency for most production workloads. The maximum_lag_on_failover parameter defines the acceptable data loss threshold during automatic failover.

    For use cases requiring strict data durability, enable synchronous replication by setting synchronous_mode: true in the DCS. Patroni automatically manages PostgreSQL’s synchronous_standby_names to ensure every transaction is confirmed by at least one replica before commit, trading write performance for zero data loss on failover.

    Patroni Alternative for Broader HA Protection with Near-Zero RPO

    If your environment is simple and only running on PostgreSQL, Patroni is a good choice. But for organizations that need HA beyond PostgreSQL or want to protect the availability of the entire application and its underlying workload, i2Availability is a better choice.

    i2Availability is an application-level high availability solution designed for critical workloads across physical, virtual, and hybrid environments. It uses real-time byte-level replication and automated failover to protect workloads and support business continuity with near-zero RPO and very low RTO.

    Key strengths of i2Availability:

    • Heterogeneous coverage: Protects PostgreSQL, Oracle, SQL Server, MySQL, and many other database platforms.
    • Application-level protection: i2Availability can protect the database together with related applications and services. Custom scripts and grouped failover sequences can coordinate the recovery of multi-tier workloads.
    • Optimized for long-distance disaster recovery: Uses byte-level incremental replication to transmit only changed data, minimizing bandwidth consumption. This makes it well suited for long-distance, cross-city disaster recovery.
    • Simpler DR operations: A centralized web console provides replication monitoring, rule management, health diagnostics, failover, and failback, reducing the operational complexity of maintaining separate HA and DR components.
    • Fast, automated failover: Multi-heartbeat monitoring, node arbitration, and application-level health checks help detect server, network, OS, and application failures. Once a failure is confirmed, services can be automatically started on the standby, with virtual IP drift minimizing application disruption.

    You can click the button below to request a 60-day free trial:

    FREE Trial for 60-Day
    Secure Download

    Conclusion

    This is all for Patroni PostgreSQL setup. This process transforms standalone PostgreSQL into a resilient database platform with automated failover and consistent configuration management. It remains the ideal choice for pure PostgreSQL environments

    For organizations requiring comprehensive business continuity, multi-database coverage, or long-distance cross-regional disaster recovery, Info2soft‘s i2Availability is more recommended.

    Dylan has 8+ years of experience in enterprise data management, server optimization, and disaster recovery. He specializes in translating complex technical concepts into actionable guides for IT administrators and DevOps teams, with a focus on data security, cloud migration, and business continuity.

    More Related Articles

    Ready to Enhance Business Data Security?

    · Enterprise & Mid-market Customers Worldwide

    · Support team available to assist you throughout your trial

    · Start a 60-day free trial or view demo to see how Info2Soft protects enterprise data.

    Please fill out the form and submit it, our customer service representative will contact you soon.
    By submitting this form, I confirm that I have read and agree to the Privacy Notice.
    {{ isSubmitting ? 'Submitting...' : 'Submit' }}