A PostgreSQL active-active architecture keeps multiple database nodes available for read and write traffic, reducing maintenance downtime and avoiding a single primary bottleneck for client connections.
In a Pacemaker and Corosync cluster, the pcs CLI can manage a systemd unit as a cluster resource and clone that resource so the service stays started on every node. Health checks are performed by Pacemaker based on the configured monitor operation, while traffic distribution is handled outside the cluster by a load balancer, DNS, or application-side routing.
Cloning a PostgreSQL service provides supervision and restart behavior, not multi-writer replication. A true active-active deployment requires a multi-primary replication layer (such as BDR or an equivalent solution) and separate local data directories on each node; cloning a shared-storage database instance can corrupt the data directory. Quorum, fencing, and replication health should be correct before allowing write traffic to land on multiple nodes.
Steps to set up PostgreSQL active-active with PCS:
- Confirm the cluster is online with quorum.
$ sudo pcs status Cluster name: clustername Cluster Summary: * Stack: corosync (Pacemaker is running) * Current DC: node-01 (version 2.1.6-6fdc9deea29) - partition with quorum * Last updated: Thu Jan 1 05:41:07 2026 on node-01 * Last change: Thu Jan 1 05:41:04 2026 by root via cibadmin on node-01 * 3 nodes configured * 0 resource instances configured Node List: * Online: [ node-01 node-02 node-03 ] Full List of Resources: * No resources Daemon Status: corosync: active/enabled pacemaker: active/enabled pcsd: active/enabled
- Identify the PostgreSQL service unit name used on the cluster nodes.
$ systemctl list-unit-files --type=service | grep -E '^postgresql.*\.service' postgresql.service disabled enabled postgresql@.service indirect enabled
Use the unit name without the trailing .service in the resource agent, such as systemd:postgresql, systemd:postgresql-15, or systemd:postgresql@15-main.
- Create the PostgreSQL service resource.
$ sudo pcs resource create postgresql_service systemd:postgresql@16-main op monitor interval=30s
Replace systemd:postgresql with the unit name found in the previous step when a versioned or templated unit is used.
Related: How to create a Pacemaker resource
- Clone the PostgreSQL service resource across nodes.
$ sudo pcs resource clone postgresql_service meta clone-max=2 clone-node-max=1
Omit clone-max to default to one instance per cluster node.
Cloning a PostgreSQL instance that uses shared storage for a single data directory can cause immediate data corruption.
- Verify the cloned resource status.
$ sudo pcs status resources * Clone Set: postgresql_service-clone [postgresql_service]: * postgresql_service (systemd:postgresql@16-main): Starting node-02 * Started: [ node-01 ] * Stopped: [ node-03 ] - Verify each node accepts database connections before routing client traffic.
$ pg_isready -h node-01 -p 5432 node-01:5432 - accepting connections $ pg_isready -h node-02 -p 5432 node-02:5432 - accepting connections
- Update client routing to distribute traffic across active nodes.
- Run a failover test to confirm routing behaves correctly when a node is unavailable.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
