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:

  1. 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
  2. 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.

  3. 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.

  4. 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.

  5. 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 ]
  6. 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
  7. Update client routing to distribute traffic across active nodes.
  8. Run a failover test to confirm routing behaves correctly when a node is unavailable.