Managing PostgreSQL Clusters
Quick Reference
| Action | Command | Description |
|---|---|---|
| Create Cluster | bin/pgsql-add <cls> |
Create a new PostgreSQL cluster |
| Expand Cluster | bin/pgsql-add <cls> <ip...> |
Add replica to existing cluster |
| Shrink Cluster | bin/pgsql-rm <cls> <ip...> |
Remove instance from cluster |
| Remove Cluster | bin/pgsql-rm <cls> |
Destroy entire PostgreSQL cluster |
| Reload Service | bin/pgsql-svc <cls> [ip...] |
Reload cluster load balancer config |
| Reload HBA | bin/pgsql-hba <cls> [ip...] |
Reload cluster HBA access rules |
| Clone Cluster | - | Clone via standby cluster or PITR |
For other management tasks, see: HA Management, Manage Users, Manage Databases.
Create Cluster
To create a new PostgreSQL cluster, first define the cluster in the inventory, then add nodes and initialize:
On managed nodes, create the cluster with: (Execute pgsql.yml playbook on <cls> group)
Example: Create 3-node PG cluster pg-test
If you re-run create on an existing cluster, Pigsty won’t remove existing data files, but service configs will be overwritten and the cluster will restart!
Additionally, if you specified a baseline SQL in database definition, it will re-execute - if it contains delete/overwrite logic, data loss may occur.
Expand Cluster
To add a new replica to an existing PostgreSQL cluster, add the instance definition to inventory: all.children.<cls>.hosts.
Scaling out is similar to creating a cluster. First add the new node to Pigsty: Add Node:
Then run the following on the new node to scale out (Install PGSQL module on new node with same pg_cluster):
After scaling, you should Reload Service to add the new member to load balancer.
Example: Add replica 10.10.10.13 to 2-node cluster pg-test
Shrink Cluster
To remove a replica from an existing PostgreSQL cluster, remove the instance definition from inventory all.children.<cls>.hosts.
Scale-in stops the instance and deletes its data directory by default. First run pig pg list <cls> and pig pb info, verify that the target is not the primary and that a recent restorable backup exists,
then have the operator enter the exact <ip> and execute only after confirmation.
First uninstall PGSQL module from target node (Execute pgsql-rm.yml on <ip>):
After removing PGSQL module, optionally remove the node from Pigsty: Remove Node:
After scaling in, remove the instance from inventory, then Reload Service to remove it from load balancer.
Example: Remove replica 10.10.10.13 from 3-node cluster pg-test
Remove Cluster
To destroy a cluster, uninstall PGSQL module from all nodes (Execute pgsql-rm.yml on <cls>):
This is irreversible data deletion. Inspect pig pg list <cls> and pig pb info, verify a recent backup and any independent copy to retain,
and have the operator enter the exact cluster name. The commands below perform the corresponding destruction directly.
After destroying PGSQL, optionally remove all nodes from Pigsty: Remove Node (optional if other services exist):
After removal, delete the entire cluster definition from inventory.
Example: Destroy 3-node PG cluster pg-test
Note: If pg_safeguard is configured (or globally true), pgsql-rm.yml will abort to prevent accidental removal.
Override with playbook command line to force removal.
By default, cluster backup repo is deleted with the cluster. To preserve backups (e.g., with centralized repo), set pg_rm_backup=false:
Reload Service
PostgreSQL clusters expose services via HAProxy on host nodes. When service definitions, instance weights, or cluster membership change (for example, scale out or scale in), reload services to update HAProxy’s static member configuration. The default Primary and Replica services detect the current role through Patroni REST API health checks, so ordinary switchover or failover reroutes automatically and does not require regenerating HAProxy configuration.
To reload service config on entire cluster or specific instances (Execute pg_service subtask of pgsql.yml on <cls> or <ip>):
If you use a dedicated load-balancer cluster (pg_service_provider), only reloading the cluster primary updates the load-balancer configuration.
Example: Reload pg-test cluster service config
Reload HBA
When HBA configs change, reload HBA rules to apply. (pg_hba_rules / pgb_hba_rules)
If you have inventory-role-specific HBA rules or address ranges that reference cluster member aliases, reload HBA after changing pg_role labels or scaling the cluster. Role selectors use static inventory variables and do not change automatically after a Patroni switchover.
To reload PG and Pgbouncer HBA rules on entire cluster or specific instances (Execute HBA subtasks of pgsql.yml on <cls> or <ip>):
Example: Reload pg-test cluster HBA rules
Config Cluster
PostgreSQL config params are managed by Patroni. Initial params are specified by Patroni config template.
After cluster init, config is stored in Etcd, dynamically managed and synced by Patroni.
Most Patroni config params can be modified via patronictl.
Other params (e.g., etcd DCS config, log/RestAPI config) can be updated via subtasks. For example, when etcd cluster membership changes, refresh Patroni config:
You can override Patroni-managed defaults at different levels: specify params per instance, specify params per user, or specify params per database.
Clone Cluster
Two ways to clone a cluster: use Standby Cluster, or use Point-in-Time Recovery. The former is simple and requires no backup repository, but it does require a reachable replication upstream and can clone only the latest state. The latter requires a centralized backup repository such as Silo and can clone to any point within the retention period.
| Method | Pros | Cons | Use Cases |
|---|---|---|---|
| Standby Cluster | No backup repository needed | Requires reachable upstream; latest state only | DR, read-write separation, migration |
| PITR | Recover to any point | Requires centralized backup | Undo mistakes, data audit |
Clone via Standby Cluster
Standby Cluster continuously syncs from upstream cluster via streaming replication - the simplest cloning method.
Specify pg_upstream on the new cluster primary to auto-pull data from upstream.
Create standby cluster with:
Standby cluster follows upstream, keeping data in sync. Promote to independent cluster anytime:
Example: Promote Standby to Independent Cluster
Via Config Cluster, remove standby_cluster config to promote:
After promotion, pg-test2 becomes independent cluster accepting writes, forked from pg-test.
Example: Change Replication Upstream
If upstream cluster switchover occurs, change standby cluster upstream via Config Cluster:
Clone via PITR
Point-in-Time Recovery (PITR) allows recovery to any point within backup retention. Requires a centralized backup repository (Silo/S3), but is more powerful.
To clone via PITR, add pg_pitr param specifying recovery target:
Execute clone with pgsql-pitr.yml playbook:
PITR supports multiple recovery target types:
| Target Type | Example | Description |
|---|---|---|
| Time | time: "2025-01-10 10:00:00+00" |
Recover to specific timestamp |
| XID | xid: "250000" |
Recover to before/after txn |
| Name | name: "before_migration" |
Recover to named restore point |
| LSN | lsn: "0/4001C80" |
Recover to specific WAL pos |
| Latest | pg_pitr: {} |
Recover to end of WAL archive |
Pigsty v5.0 PITR keeps archiving enabled by default (archive: true). If you explicitly set archive: false for exploratory recovery, reset archive_mode, restart the cluster, and perform a new full backup after confirming the recovered data is correct:
For detailed PITR usage, see Restore Operations documentation.