PostgreSQL Patroni Cluster Introduction,
Configuration, Implementation
And Administration
Step by Step
Document
Author : Ahsan Iqbal
Created date : 11th August, 2025
Doc Version : V-1.0
Reviewer:
V# Name Designation Email Address Company
Database Administrator
V-1.1 Syed Asad [Link]@[Link] Securemax
V-1.1 Sharukh Shaikh Database Administrator Sharukhshaikh1807@[Link] Securemax
Page 2 of 20
1. Introduction ................................................................................................................................................. 4
2. Overview of Architecture Components ................................................................................................. 4
3. Pre-installation Prerequisites ...................................................................................................................... 5
3.1 Open the network Ports ................................................................................................................... 5
3.2 Download software / Media ............................................................................................................ 6
3.3 Modify the /etc/hosts file to include the hostnames and IP addresses of the nodes ........................... 6
4. Install PostgreSQL, Patroni, ETCD & Pgbouncer on Data nodes .................................................................. 7
4.1 Install PostgreSQL ............................................................................................................................. 7
4.2 Install Patroni ....................................................................................................................................... 7
4.3 Install ETCD ......................................................................................................................................... 7
4.4 Install Pgbouncer ................................................................................................................................. 7
4.5 Check the status of PostgreSQL, patroni, etcd .................................................................................... 8
4.6 Disable the services .......................................................................................................................... 8
5. Configure etcd distributed store ................................................................................................................. 9
5.1 Modify the configuration file ........................................................................................................... 9
5.2 Enable and start the etcd service on all nodes ........................................................................... 10
5.3 Check the etcd cluster members and leader Node ......................................................................... 11
6. Configure Patroni .................................................................................................................................... 11
6.1 Create the /etc/patroni/[Link] configuration file and add the following configuration for each
Patroni Node ...................................................................................................................................... 11
6.2 Check the patroni. service file if it is not created create it manually & Reload the systemd to be
aware of the new service ................................................................................................................... 16
6.3 Start the Patroni service on each Node one by one .......................................................................... 16
6.4 Check for any errors of the patroni services ............................................................................... 16
6.5 Check the cluster status ................................................................................................................. 16
7. Configure the PgBouncer ....................................................................................................................... 17
8. Configure the HAProxy ............................................................................................................................... 18
9. Basic Administration and Troubleshooting Commands ..................................................................... 19
10. References ................................................................................................................................................. 20
Page 3 of 20
1. Introduction
This document outlines the installation and configuration process for a high-availability (HA) database
architecture designed to ensure robust performance and failover capabilities. The architecture leverages
a combination of HAProxy load balancers, PostgreSQL databases with Patroni for automated failover,
and PgBouncer for connection pooling. It is structured to support a primary Data Center (MAIN DC) with
a Disaster Recovery (DC DR) site, ensuring continuous operation and data integrity under various failure
scenarios.
2. Overview of Architecture Components
HAProxy: Acts as a load balancer and reverse proxy, distributing incoming application traffic across the
database nodes in both MAIN DC and DC DR. It ensures high availability and efficient load distribution.
Patroni: A template for high-availability PostgreSQL clusters, managing automated failover and
replication between primary and standby nodes to maintain data consistency and availability.
PgBouncer: A lightweight connection pooler for PostgreSQL, optimizing database connections by reusing
them, reducing resource usage, and improving performance.
PostgreSQL Nodes: Include a Primary Node (active) and Standby Nodes (replicas) in both MAIN DC and
DC DR. The Primary Node handles read/write operations, while Standby Nodes provide redundancy and
support read-only queries.
PSR (Primary-Standby Replication): Facilitates real-time data replication from the Primary Node to
Standby Nodes, ensuring data synchronization across the architecture.
Applications: Client applications that interact with the database infrastructure through HAProxy,
Page 4 of 20
enabling seamless access to the underlying PostgreSQL clusters.
3. Pre-installation Prerequisites
3.1 Server and their Roles.
Network Ports Used by different components:
S# Component Name Ports
1 PostgreSQL 15432
2 Patroni 8010
3 Etcd 23790 & 23805
4 Pgbouncer 5005
5 HAProxy 5005
IP Role
[Link] Primary server
[Link] Replica server
[Link] HA proxy server in Main Datacenter
[Link] Replica Server
[Link] HA Proxy Server in DR
Page 5 of 20
3.2 Download software
Download PostgreSQL software using below links:
[Link]
[Link]
[Link]
[Link]
Download Patroni Media using below links:
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
Download Etcd Media using below links:
[Link]
1PGDG.rhel8.x86_64.rpm
Download HAProxy Media using below links:
[Link]
1PGDG.rhel8.x86_64.rpm
Download Pgbouncer using below link:
[Link]
3.3 Modify the /etc/hosts file to include the hostnames and IP addresses of the nodes
Add the following changes on each node in hosts file. (vi /etc/hosts)
[Link] [Link]
[Link] [Link]
[Link] [Link]
[Link] [Link]
[Link] [Link]
Page 6 of 20
4. Install PostgreSQL, Patroni, ETCD & Pgbouncer on Data nodes
In this section we will install PostgreSQL, Patroni, ETCD, and pgbouncer on all the three data nodes.
4.1 Install PostgreSQL
On Data nodes:
yum install postgresql16-16.6-1PGDG.rhel8.x86_64.rpm
yum install postgresql16-contrib-16.6-1PGDG.rhel8.x86_64.rpm
yum install postgresql16-libs-16.6-1PGDG.rhel8.x86_64.rpm
yum install postgresql16-server-16.6-1PGDG.rhel8.x86_64.rpm
4.2 Install Patroni
On Data nodes:
yum install python3-cdiff >>> dependencies python3 3.6
yum install python3-click
yum install python3-prettytable
yum install python3-ydiff
yum install [Link]
yum install [Link]
4.3 Install ETCD
On Data nodes:
yum install etcd-3.5.9-1.rhel8.x86_64.rpm
4.4 Install Pgbouncer
PgBouncer depends on few things to get compiled:
o GNU Make 3.81+
o Libevent 2.0+
o pkg-config
o OpenSSL 1.0.1+ for TLS support
When dependencies are installed just run:
$ ./configure --prefix=/usr/local
$ make
$ make install
Page 7 of 20
4.5 Check the status of PostgreSQL, patroni, etcd
# systemctl status {[Link],etcd,patroni}
● [Link] - PostgreSQL 16 database server
Loaded: loaded (/usr/lib/systemd/system/[Link]; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: [Link]
● [Link] - Etcd Server
Loaded: loaded (/usr/lib/systemd/system/[Link]; disabled; vendor preset: disabled)
Active: inactive (dead)
● [Link] - Runners to orchestrate a high-availability PostgreSQL
Loaded: loaded (/usr/lib/systemd/system/[Link]; disabled; vendor preset: disabled)
Active: inactive (dead)
4.6 Disable the services
# systemctl disable {[Link],etcd,patroni}
Page 8 of 20
5. Configure etcd distributed store
5.1 Modify the configuration file
Node-1:
# cd /etc/etcd
# ls -l
total 4
-rw-r--r--. 1 root root 1568 Feb 9 07:06 [Link]
/*Change the settigns accordingly*/
# cat [Link]
# [member]
ETCD_NAME='node-1'
ETCD_DATA_DIR="/var/lib/etcd/[Link]"
ETCD_LISTEN_PEER_URLS="[Link]
ETCD_LISTEN_CLIENT_URLS="[Link]
#[cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS="[Link]
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e.
"test=[Link]
ETCD_INITIAL_CLUSTER="node-1=[Link]
3=[Link]
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="Postgres_HA_Cluster"
ETCD_ADVERTISE_CLIENT_URLS="[Link]
Node-2:
# cd /etc/etcd
# ls -l
total 4
-rw-r--r--. 1 root root 1568 Feb 9 07:06 [Link]
# [member]
ETCD_NAME='node-2'
ETCD_DATA_DIR="/var/lib/etcd/[Link]"
ETCD_LISTEN_PEER_URLS="[Link]
ETCD_LISTEN_CLIENT_URLS="[Link]
Page 9 of 20
#[cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS="[Link]
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=[Link]
ETCD_INITIAL_CLUSTER="node-1=[Link]
3=[Link]
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="Postgres_HA_Cluster"
ETCD_ADVERTISE_CLIENT_URLS="[Link]
Node-3:
# cd /etc/etcd
# ls -l
total 4
-rw-r--r--. 1 root root 1568 Feb 9 07:06 [Link]
# [member]
ETCD_NAME='node-3'
ETCD_DATA_DIR="/var/lib/etcd/[Link]"
ETCD_LISTEN_PEER_URLS="[Link]
ETCD_LISTEN_CLIENT_URLS="[Link]
#[cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS="[Link]
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=[Link]
ETCD_INITIAL_CLUSTER="node-1=[Link]
3=[Link]
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="Postgres_HA_Cluster"
ETCD_ADVERTISE_CLIENT_URLS="[Link]
5.2 Enable and start the etcd service on all nodes:
systemctl enable --now etcd
systemctl start etcd
systemctl status etcd
/*Try starting all nodes at the same time for the etcd cluster to be created.
It may fail during startup try to start it again and double check the configuration file. */
Page 10 of 20
5.3 Check the etcd cluster members and leader Node
ETCDCTL_API=3 etcdctl --
endpoints=[Link] -w table member list
ETCDCTL_API=3 etcdctl --
endpoints=[Link] -w table member
endpoint status
6. Configure Patroni
6.1 Create the /etc/patroni/[Link] configuration file and add the following
configuration for each Patroni Node
Node-1:
scope: pci-cluster
namespace: db
name: [Link]
restapi:
listen: [Link]:8010
connect_address: [Link]:8010
etcd3:
hosts: [Link]:23790,[Link]:23790,[Link]:23790
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
shared_buffers: 4GB
Page 11 of 20
max_wal_size: 2GB
min_wal_size: 1GB
log_rotation_size: 100MB
max_connections: 300
wal_level: replica
wal_log_hints: "on"
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
archive_mode: "on"
archive_command: 'cp %p /pgarchive/16/archive/%f'
log_rotation_size: 100MB
log_destination: 'stderr'
logging_collector: 'on'
log_directory: '/pglog/postgres_log'
log_filename: 'postgresql-%Y-%m-%d_%H%M%[Link]'
pg_hba:
- host replication replicator [Link]/0 md5
- host replication replicator [Link]/0 md5
- host replication replicator [Link]/0 md5
- host replication all [Link]/0 md5
- host all all [Link]/0 md5
postgresql:
listen: [Link]:15432
connect_address: [Link]:15432
data_dir: /pgdata/16
bin_dir: /usr/pgsql-16/bin
authentication:
replication:
username: replicator
password: replicator
superuser:
username: postgres
password: postgres
parameters:
unix_socket_directories: '/tmp/'
watchdog:
mode: required
device: /dev/watchdog
safety_margin: 5
tags:
failover_priority: 2
noloadbalance: false
clonefrom: false
nosync: false
log:
level: DEBUG
dir: /pglog/patroni_log
file_size: 100000000
file_num: 10
Page 12 of 20
scope: pci-cluster
namespace: db
name: [Link]
restapi:
listen: [Link]:8010
connect_address: [Link]:8010
etcd3:
hosts: [Link]:23790,[Link]:23790,[Link]:23790
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
shared_buffers: 4GB
max_wal_size: 2GB
min_wal_size: 1GB
log_rotation_size: 100MB
max_connections: 300
wal_level: replica
wal_log_hints: "on"
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
archive_mode: "on"
archive_command: 'cp %p /pgarchive/16/archive/%f'
log_rotation_size: 100MB
log_destination: 'stderr'
logging_collector: 'on'
log_directory: '/pglog/postgres_log'
log_filename: 'postgresql-%Y-%m-%d_%H%M%[Link]'
pg_hba:
- host replication replicator [Link]/0 md5
- host replication replicator [Link]/0 md5
- host replication replicator [Link]/0 md5
- host replication all [Link]/0 md5
- host all all [Link]/0 md5
postgresql:
listen: [Link]:15432
connect_address: [Link]:15432
data_dir: /pgdata/16
bin_dir: /usr/pgsql-16/bin
authentication:
replication:
username: replicator
password: replicator
Page 13 of 20
superuser:
username: postgres
password: postgres
parameters:
unix_socket_directories: '/tmp/'
watchdog:
mode: required
device: /dev/watchdog
safety_margin: 5
tags:
failover_priority: 2
noloadbalance: false
clonefrom: false
nosync: false
log:
level: DEBUG
dir: /pglog/patroni_log
file_size: 100000000
file_num: 10
Node-3:
scope: pci-cluster
namespace: db
name: [Link]
restapi:
listen: [Link]:8010
connect_address: [Link]:8010
etcd3:
hosts: [Link]:23790,[Link]:23790,[Link]:23790
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
shared_buffers: 4GB
max_wal_size: 2GB
min_wal_size: 1GB
log_rotation_size: 100MB
max_connections: 300
wal_level: replica
Page 14 of 20
wal_log_hints: "on"
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
archive_mode: "on"
archive_command: 'cp %p /pgarchive/16/archive/%f'
log_rotation_size: 100MB
log_destination: 'stderr'
logging_collector: 'on'
log_directory: '/pglog/postgres_log'
log_filename: 'postgresql-%Y-%m-%d_%H%M%[Link]'
pg_hba:
- host replication replicator [Link]/0 md5
- host replication replicator [Link]/0 md5
- host replication replicator [Link]/0 md5
- host replication all [Link]/0 md5
- host all all [Link]/0 md5
postgresql:
listen: [Link]:15432
connect_address: [Link]:15432
data_dir: /pgdata/16
bin_dir: /usr/pgsql-16/bin
authentication:
replication:
username: replicator
password: replicator
superuser:
username: postgres
password: postgres
parameters:
unix_socket_directories: '/tmp/'
watchdog:
mode: required
device: /dev/watchdog
safety_margin: 5
tags:
failover_priority: 2
noloadbalance: false
clonefrom: false
nosync: false
log:
level: DEBUG
dir: /pglog/patroni_log
file_size: 100000000
file_num: 10
Page 15 of 20
6.2 Check the patroni. service file if it is not created create it manually & Reload the
systemd to be aware of the new service
sudo systemctl daemon-reload
Repeat the above steps on each node.
6.3 Start the Patroni service on each Node one by one:
Note:
Follow these steps to apply the commands:
o Start with node1 – Run the commands and wait for the service to become active.
o Proceed to the next node – Only after node1 is live, move to node2 and apply the commands.
o Verify synchronization – Ensure the new node syncs with the primary before proceeding.
o Repeat for remaining nodes – Continue this process one node at a time.
/*start the patroni service on node-1*/
sudo systemctl enable --now patroni
sudo systemctl restart patroni
sudo systemctl status patroni
6.4 Check for any errors of the patroni services:
sudo journalctl -u patroni. service --follow
6.5 Check the cluster status
patronictl -c /etc/patroni/[Link] list
Page 16 of 20
7. Configure the Pgbouncer
1. PgBouncer Configuration File ([Link])
[databases]
# To set the pool mode at the database level
# [Database Name] = host=[Host Name] port= 15432 auth_user=postgres pool_mode=session
pms_prod = host=[Link] port=15432 auth_user=postgres pool_mode=session
* = host=[Link] port=15432 auth_user=postgres
[pgbouncer]
logfile = /pglog/pgbouncer/[Link]
pidfile = /pghome/pgbouncer/[Link]
listen_addr = [Link]
listen_port = 25432
auth_type = md5
auth_file = /pghome/pgbouncer/[Link]
auth_query = SELECT usename, passwd FROM pg_shadow WHERE usename=$1
admin_users = postgres
stats_users = postgres
pool_mode = transaction
ignore_startup_parameters = extra_float_digits
max_client_conn = 500
default_pool_size = 100
reserve_pool_size = 15
reserve_pool_timeout = 3
server_lifetime = 300
server_idle_timeout = 120
server_connect_timeout = 5
server_login_retry = 1
query_timeout = 300
query_wait_timeout = 60
client_idle_timeout = 90
client_login_timeout = 60
2. User Authentication Configuration ([Link])
"postgres" "Admin#$321"
Follow the same steps on the other nodes as well and change the hostname accordingly.
3. Starting, Stopping & Restarting PgBouncer
Page 17 of 20
8. Configure the HAProxy
1. Edit the [Link] file using root user.
global
maxconn 2000
user haproxy
group haproxy
daemon
defaults
mode tcp
log global
option tcplog
retries 3
timeout queue 1m
timeout connect 4s
timeout client 60m
timeout server 60m
timeout check 5s
maxconn 1000
listen stats
mode http
bind *:7000
stats enable
stats uri /
listen primary
bind *:5005
mode tcp
option ssl-hello-chk # Optional: Ensures SSL handshake is valid
option httpchk OPTIONS /master
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server [Link] [Link]:25432 maxconn 700 check port 8010
server [Link] [Link]:25432 maxconn 700 check port 8010
server [Link] [Link]:25432 maxconn 700 check port 8010
2. Stop & Start HAProxy.
sudo systemctl stop [Link]
sudo systemctl start [Link]
sudo systemctl status [Link]
3. Monitoring and Troubleshooting.
sudo journalctl -u [Link] -f
Similarly configure the other HAProxy Node.
Page 18 of 20
9. Basic Administration and Troubleshooting Commands
In this section we will cover some basic commands for etcd, patroni & pgbouncer.
Basic Commands
S# Commands Description
Etcd Commands
01 ETCDCTL_API=3 etcdctl --write-out=table endpoint health To check etcd cluster health
02 ETCDCTL_API=3 etcdctl --write-out=table endpoint status To check cluster Status
03 ETCDCTL_API=3 etcdctl --write-out=table member list List All Members
04 ETCDCTL_API=3 etcdctl --write-out=table alarm list Check Alarm List (for issues like no space,
corruption)
Patroni Commands
07 patronictl -c /etc/patroni/[Link] list To check patroni cluster Status, leader,
replication lag
08 patronictl -c /etc/patroni/[Link] show-config Displays Patroni configuration (PostgreSQL
parameters)
09 journalctl -u patroni -f Check PostgreSQL Logs
10 patronictl -c /etc/patroni/[Link] switchover Graceful Switchover
11 patronictl -c /etc/patroni/[Link] pause [cluster name] Pause Auto-Failove (useful for
maintenance)
12 patronictl -c /etc/patroni/[Link] resume [cluster name] Resume Auto-Failover
13 patronictl -c /etc/patroni/[Link] reload Reload Configuration:
Applies configuration changes without a
full restart.
Pgbouncer Commands
14 psql -p 25432 -U postgres -d pgbouncer Basic Connection Test
15 SHOW HELP; Lists All Admin Commands
16 SHOW DATABASES; Configured databases
17 SHOW POOLS; Connection pool stats
18 SHOW CLIENTS; Active clients
19 SHOW SERVERS; PostgreSQL backend connections
20 SHOW STATS; Traffic statistics (queries, bytes)
21 pgbouncer -R -d /pghome/pgbouncer/[Link] OR reload; Reload Configuration (Without Restart)
22 SHOW CONFIG; Runtime Configuration
Page 19 of 20
References
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
Page 20 of 20