This is the multi-page printable view of this section. .
Configuration
- 1: Cluster / Instance
- 2: Kernel Version
- 3: Package Alias
- 4: User/Role
- 5: Database
- 6: HBA Rules
- 7: Access Control
- 8: Parameters
Pigsty is a “configuration-driven” PostgreSQL platform: all behaviors come from the combination of inventory files in ~/pigsty/conf/*.yml and PGSQL parameters.
Once you’ve written the configuration, you can replicate a customized cluster with instances, users, databases, access control, extensions, and tuning policies in just a few minutes.
Configuration Entry
- Prepare Inventory: Copy a
pigsty/conf/*.ymltemplate or write an Ansible Inventory from scratch, placing cluster groups (all.children.<cls>.hosts) and global variables (all.vars) in the same file. - Define Parameters: Override the required
PGSQLparameters in thevarsblock. The override order from global → cluster → host determines the final value. - Apply Configuration: Run
./configure -c <conf>orbin/pgsql-add <cls>and other playbooks to apply the configuration. Pigsty will generate the configuration files needed for Patroni/pgbouncer/pgbackrest based on the parameters.
Pigsty’s default demo inventory conf/pgsql.yml is a minimal example: one pg-meta cluster, global pg_version: 18, and a few business user and database definitions. You can expand with more clusters from this base.
Focus Areas & Documentation Index
Pigsty’s PostgreSQL configuration can be organized from the following dimensions. Subsequent documentation will explain “how to configure” each:
- Cluster & Instances: Define instance topology (standalone, primary-replica, standby cluster, delayed cluster, Citus, etc.) through
pg_cluster / pg_role / pg_seq / pg_upstream. - Kernel Version: Select the core version, flavor, and tuning templates using
pg_version,pg_mode,pg_packages,pg_extensions,pg_conf, and other parameters. - Users/Roles: Declare system roles, business accounts, password policies, and connection pool attributes in
pg_default_rolesandpg_users. - Database Objects: Create databases as needed using
pg_databases,baseline,schemas,extensions,pool_*fields and automatically integrate with pgbouncer/Grafana. - Access Control (HBA): Maintain host-based authentication policies using
pg_default_hba_rulesandpg_hba_rulesto ensure access boundaries for different roles/networks. - Privilege Model (ACL): Converge object privileges through
pg_default_privileges,pg_default_roles,pg_revoke_publicparameters, providing an out-of-the-box layered role system.
After understanding these parameters, you can write declarative inventory manifests as “configuration as infrastructure” for any business requirement. Pigsty will handle execution and ensure idempotency.
A Typical Example
The following snippet shows how to control instance topology, kernel version, extensions, users, and databases in the same configuration file:
- The
pg-analyticscluster contains one primary and one offline replica. - Global settings specify
pg_version: 18with a set of extension examples and loadolap.ymltuning. - Declare business objects in
pg_databasesandpg_users, automatically generating schema/extension and connection pool entries. - Additional
pg_hba_rulesrestrict access sources and authentication methods.
Modify and apply this inventory to get a customized PostgreSQL cluster without manual configuration.
1 - Cluster / Instance
Choose the appropriate instance and cluster types based on your requirements to configure PostgreSQL database clusters that meet your needs.
You can define different types of instances and clusters. Here are several common PostgreSQL instance/cluster types in Pigsty:
- Primary: Define a single instance cluster.
- Replica: Define a basic HA cluster with one primary and one replica.
- Offline: Define an instance dedicated to OLAP/ETL/interactive queries
- Sync Standby: Enable synchronous commit to ensure no data loss.
- Quorum Commit: Use quorum sync commit for a higher consistency level.
- Standby Cluster: Clone an existing cluster and follow it
- Delayed Cluster: Clone an existing cluster for emergency data recovery
- Citus Cluster: Define a Citus distributed database cluster
Primary
We start with the simplest case: a single instance cluster consisting of one primary:
This configuration is concise and self-describing, consisting only of identity parameters. Matching the Ansible group name to pg_cluster remains convenient for -l pg-test, but it is not a hard membership constraint. Current code discovers actual members from each host’s pg_cluster identity, so one PostgreSQL cluster may span multiple inventory groups.
Use the following command to create this cluster:
For demos, development testing, hosting temporary requirements, or performing non-critical analytical tasks, a single database instance may not be a big problem. However, such a single-node cluster has no high availability. When hardware failures occur, you’ll need to use PITR or other recovery methods to ensure the cluster’s RTO/RPO. For this reason, you may consider adding several read-only replicas to the cluster.
Replica
To add a read-only replica instance, you can add a new node to pg-test and set its pg_role to replica.
If the entire cluster doesn’t exist, you can directly create the complete cluster. If the cluster primary has already been initialized, you can add a replica to the existing cluster:
When the cluster primary fails, the read-only instance (Replica) can take over the primary’s work with the help of the high availability system. Additionally, read-only instances can be used to execute read-only queries: many businesses have far more read requests than write requests, and most read-only query loads can be handled by replica instances.
Offline
Offline instances are dedicated read-only replicas specifically for serving slow queries, ETL, OLAP traffic, and interactive queries. Slow queries/long transactions have adverse effects on the performance and stability of online business, so it’s best to isolate them from online business.
To add an offline instance, assign it a new instance and set pg_role to offline.
Dedicated offline instances work similarly to common replica instances, but they serve as backup servers in the pg-test-replica service. That is, only when all replica instances are down will the offline and primary instances provide this read-only service.
In many cases, database resources are limited, and using a separate server as an offline instance is not economical. As a compromise, you can select an existing replica instance and mark it with the pg_offline_query flag to indicate it can handle “offline queries”. In this case, this read-only replica will handle both online read-only requests and offline queries. You can use pg_default_hba_rules and pg_hba_rules for additional access control on offline instances.
Sync Standby
When Sync Standby is enabled, PostgreSQL will select one replica as the sync standby, with all other replicas as candidates. The primary database will wait for the standby instance to flush to disk before confirming commits. The standby instance always has the latest data with no replication lag, and primary-standby switchover to the sync standby will have no data loss.
PostgreSQL uses asynchronous streaming replication by default. If the primary fails, WAL that has not yet replicated may be lost. pg_rpo is Patroni’s sampled lag threshold for failover candidates, not a hard upper bound on actual loss; the real window also depends on write rate, replication state, and Patroni sampling timing.
However, in some critical scenarios (e.g., financial transactions), data loss is completely unacceptable, or read replication lag is unacceptable. In such cases, you can use synchronous commit to solve this problem. To enable sync standby mode, you can simply use the crit.yml template in pg_conf.
To enable sync standby on an existing cluster, configure the cluster and enable synchronous_mode:
In this case, the PostgreSQL configuration parameter synchronous_standby_names is automatically managed by Patroni.
One replica will be elected as the sync standby, and its application_name will be written to the PostgreSQL primary configuration file and applied.
Quorum Commit
Quorum Commit provides more powerful control than sync standby: especially when you have multiple replicas, you can set criteria for successful commits, achieving higher/lower consistency levels (and trade-offs with availability).
If you want at least two replicas to confirm commits, you can adjust the synchronous_node_count parameter through Patroni cluster configuration and apply it:
If you want to use more sync replicas, modify the synchronous_node_count value. When the cluster size changes, you should ensure this configuration is still valid to avoid service unavailability.
In this case, the PostgreSQL configuration parameter synchronous_standby_names is automatically managed by Patroni.
After applying the configuration, two sync standbys appear.
Another scenario is using any n replicas to confirm commits. In this case, the configuration is slightly different. For example, if we only need any one replica to confirm commits:
After applying, the configuration takes effect, and all standbys become regular replicas in Patroni. However, in pg_stat_replication, you can see sync_state becomes quorum.
Standby Cluster
You can clone an existing cluster and create a standby cluster for data migration, horizontal splitting, multi-region deployment, or disaster recovery.
Under normal circumstances, the standby cluster will follow the upstream cluster and keep content synchronized. You can promote the standby cluster to become a truly independent cluster.
The standby cluster definition is basically the same as a normal cluster definition, except that the pg_upstream parameter is additionally defined on the primary. The primary of the standby cluster is called the Standby Leader.
For example, below defines a pg-test cluster and its standby cluster pg-test2. The configuration inventory might look like this:
The primary node pg-test2-1 of the pg-test2 cluster will be a downstream replica of pg-test and serve as the Standby Leader in the pg-test2 cluster.
Just ensure the pg_upstream parameter is configured on the standby cluster’s primary node to automatically pull backups from the original upstream.
If necessary (e.g., upstream primary-standby switchover/failover), you can change the standby cluster’s replication upstream through cluster configuration.
To do this, simply change standby_cluster.host to the new upstream IP address and apply.
You can promote the standby cluster to an independent cluster at any time, so the cluster can independently handle write requests and diverge from the original cluster.
To do this, you must configure the cluster and completely erase the standby_cluster section, then apply.
If you specify pg_upstream on a replica instead of the primary, you can configure cascade replication for the cluster.
When configuring cascade replication, you must use the IP address of an instance in the cluster as the parameter value, otherwise initialization will fail. The replica performs streaming replication from a specific instance rather than the primary.
The instance acting as a WAL relay is called a Bridge Instance. Using a bridge instance can share the burden of sending WAL from the primary. When you have dozens of replicas, using bridge instance cascade replication is a good idea.
Delayed Cluster
A Delayed Cluster is a special type of standby cluster used to quickly recover “accidentally deleted” data.
For example, if you want a cluster named pg-testdelay whose data content is the same as the pg-test cluster from one hour ago:
You can also configure a “replication delay” on an existing standby cluster.
When some tuples and tables are accidentally deleted, you can modify this parameter to advance this delayed cluster to an appropriate point in time, read data from it, and quickly fix the original cluster.
Delayed clusters require additional resources, but are much faster than PITR and have much less impact on the system. For very critical clusters, consider setting up delayed clusters.
Citus Cluster
Pigsty natively supports Citus. You can refer to conf/ha/citus.yml as a complete example.
To define a Citus cluster, you need to specify the following parameters:
pg_modemust be set tocitus, not the defaultpgsql- The shard name
pg_shardand shard numberpg_groupmust be defined on each shard cluster pg_primary_dbmust be defined to specify the database managed by Patroni.- If you want to use
pg_dbsupostgresinstead of the defaultpg_admin_usernameto execute admin commands, thenpg_dbsu_passwordmust be set to a non-empty plaintext password
Additionally, extra hba rules are needed to allow SSL access from localhost and other data nodes. As shown below:
On the coordinator node, you can create distributed tables and reference tables and query them from any data node. Starting from 11.2, any Citus database node can act as a coordinator.
2 - Kernel Version
Choosing a “kernel” in Pigsty means determining the PostgreSQL major version, mode/distribution, packages to install, and tuning templates to load.
The Pigsty v4.5 source currently supports PostgreSQL 14-18 and uses 18 by default. The following content shows how to make these choices through configuration files.
Major Version and Packages
pg_version: Specify the PostgreSQL major version (default 18). Pigsty will automatically map to the correct package name prefix based on the version.pg_packages: Define the core package set to install, supports using package aliases (defaultpgsql-main pgsql-common, includes kernel + patroni/pgbouncer/pgbackrest and other common tools).pg_extensions: List of additional extension packages to install, also supports aliases; defaults to empty meaning only core dependencies are installed.
Effect: Ansible will pull packages corresponding to
pg_version=18during installation, pre-install extensions to the system, and database initialization scripts can then directlyCREATE EXTENSION.
Extension support varies across versions in Pigsty’s offline repository: 14 has relatively fewer available extensions, while 17/18 have the broadest coverage. If an extension is not pre-packaged, it can be added via repo_extra_packages.
Kernel Mode (pg_mode)
pg_mode controls the kernel “flavor” to deploy. Default pgsql indicates standard PostgreSQL. Pigsty currently supports the following modes:
| Mode | Scenario |
|---|---|
pgsql |
Standard PostgreSQL, HA + replication |
citus |
Citus distributed cluster, requires additional pg_shard / pg_group |
gpsql |
Cloudberry / Greenplum / MatrixDB |
mssql |
Babelfish |
mysql |
OpenGauss/HaloDB compatible with MySQL protocol |
polar |
Alibaba PolarDB (based on pg polar distribution) |
ivory |
IvorySQL (Oracle-compatible syntax) |
pgtde |
Percona PostgreSQL with pg_tde under /usr/pgtde-$v |
oriole |
OrioleDB storage engine |
agens |
AgensGraph graph database kernel |
pgedge |
pgEdge distributed replication kernel |
pg_mode determines binary paths, Patroni integration, and some kernel-specific logic; it does not automatically add every required package, extension, and business database. Use the matching conf/*.yml template in real deployments, or explicitly configure pg_packages, pg_extensions, pg_libs, and pg_databases. Here is a minimal Citus example:
conf/ha/citus.ymlprovides the current complete example. The minimal configuration above explicitly installs Citus packages and creates the extension in thecitusdatabase.
Extensions and Pre-installed Objects
Besides system packages, you can control components automatically loaded after database startup through the following parameters:
pg_libs: List to write toshared_preload_libraries. For example:pg_libs: 'timescaledb, pg_stat_statements, auto_explain'.pg_default_extensions/pg_default_schemas: Control schemas and extensions pre-created intemplate1andpostgresby initialization scripts.pg_parameters: Rendered by Pigsty intopostgresql.auto.confduring configuration. Do not also manage the same settings manually withALTER SYSTEM.
Example: Enable TimescaleDB, pgvector and customize some system parameters.
Effect: During initialization, default extensions are created in
template1andpostgres; newly created databases based ontemplate1inherit those objects.pg_parametersis written directly topostgresql.auto.conf.
Tuning Template (pg_conf)
pg_conf points to Patroni templates in roles/pgsql/templates/*.yml. Pigsty includes four built-in general templates:
| Template | Applicable Scenario |
|---|---|
oltp.yml |
Default template, for 4–128 core TP workload |
olap.yml |
Optimized for analytical scenarios |
crit.yml |
Emphasizes sync commit/minimal latency, suitable for zero-loss scenarios like finance |
tiny.yml |
Lightweight machines / edge scenarios / resource-constrained environments |
You can directly replace the template or customize a YAML file in templates/, then specify it in cluster vars.
Effect: Copy
crit.ymlas Patroni configuration, overlaypg_parameterswritten topostgresql.auto.conf, making instances run immediately in synchronous commit mode.
Combined Instance: A Complete Example
- First primary + one replica, using
olap.ymltuning. - Install PG18 plus common RAG extensions; only libraries that actually require preloading belong in
pg_libs. - Patroni/pgbouncer/pgbackrest generated by Pigsty, no manual intervention needed.
Replace the above parameters according to business needs to complete all kernel-level customization.
3 - Package Alias
PostgreSQL package naming conventions vary significantly across different operating systems:
- EL systems (RHEL/Rocky/Alma/…) use formats like
pgvector_18,postgis36_18* - Debian/Ubuntu systems use formats like
postgresql-18-pgvector,postgresql-18-postgis-3
This difference adds cognitive burden to users: you need to remember different package name rules for different systems, and handle the embedding of PostgreSQL version numbers.
Package Alias
Pigsty solves this problem through the Package Alias mechanism: you only need to use unified aliases, and Pigsty will handle all the details:
Alias Translation
Aliases can also group a set of packages as a whole. For example, Pigsty’s default installed packages - the default value of pg_packages is:
Pigsty will query the current operating system alias list (assuming el10.x86_64) and translate it to PGSQL kernel, extensions, and toolkits:
Next, Pigsty further translates pgsql-main using the currently specified PG major version (assuming pg_version = 18):
Through this approach, Pigsty shields the complexity of packages, allowing users to simply specify the functional components they want.
Which Variables Can Use Aliases?
You can use package aliases in the following four parameters, and the aliases will be automatically converted to actual package names according to the translation process:
pg_extensions- PG extension packagespg_packages- PG kernel/base utility packagesrepo_packages- Package download parameter: packages to download to local repositoryrepo_extra_packages- Extension installation parameter: additional packages to download to local repository
Alias List
You can find the alias mapping files for each operating system and architecture in the roles/node_id/vars/ directory of the Pigsty project source code:
el10.x86_64el10.aarch64el9.x86_64el9.aarch64el8.x86_64el8.aarch64u26.x86_64u26.aarch64u24.x86_64u24.aarch64u22.x86_64u22.aarch64d13.x86_64d13.aarch64d12.x86_64d12.aarch64
How It Works
Alias Translation Process
Version Placeholder
Pigsty’s alias system uses $v as a placeholder for the PostgreSQL version number. When you specify a PostgreSQL version using pg_version, all $v in aliases will be replaced with the actual version number.
For example, when pg_version: 18:
| Alias Definition (EL) | Expanded Result |
|---|---|
postgresql$v* |
postgresql18* |
pgvector_$v* |
pgvector_18* |
timescaledb-tsl_$v* |
timescaledb-tsl_18* |
| Alias Definition (Debian/Ubuntu) | Expanded Result |
|---|---|
postgresql-$v |
postgresql-18 |
postgresql-$v-pgvector |
postgresql-18-pgvector |
postgresql-$v-timescaledb-tsl |
postgresql-18-timescaledb-tsl |
Wildcard Matching
On EL systems, many aliases use the * wildcard to match related subpackages. For example:
postgis36_18*will matchpostgis36_18,postgis36_18-client,postgis36_18-utils, etc.postgresql18*will matchpostgresql18,postgresql18-server,postgresql18-libs,postgresql18-contrib, etc.
This design ensures you don’t need to list each subpackage individually - one alias can install the complete extension.
4 - User/Role
In this document, “user” refers to a logical object within a database cluster created with
CREATE USER/ROLE.
In PostgreSQL, users belong directly to the database cluster rather than a specific database. Therefore, when creating business databases and users, follow the principle of “users first, databases later”.
Pigsty defines roles and users through two config parameters:
pg_default_roles: Define globally shared roles and userspg_users: Define business users and roles at cluster level
The former defines roles/users shared across the entire environment; the latter defines business roles/users specific to a single cluster. Both have the same format as arrays of user definition objects. Users/roles are created sequentially in array order, so later users can belong to roles defined earlier.
By default, all users marked with pgbouncer: true are added to the Pgbouncer connection pool user list.
Define Users
Example from Pigsty demo pg-meta cluster:
Each user/role definition is a complex object. Only name is required:
User-level pool quota is consistently defined by
pool_connlimit(mapped to Pgbouncermax_user_connections).
Parameter Overview
The only required field is name - a valid, unique username within the cluster. All other params have sensible defaults.
| Field | Category | Type | Attr | Description |
|---|---|---|---|---|
name |
Basic | string |
Required | Username, must be valid and unique |
state |
Basic | enum |
Optional | State: create (default), absent |
password |
Basic | string |
Mutable | User password, plaintext or hash |
comment |
Basic | string |
Mutable | User comment |
login |
Privilege | bool |
Mutable | Can login, default true |
superuser |
Privilege | bool |
Mutable | Is superuser, default false |
createdb |
Privilege | bool |
Mutable | Can create databases, default false |
createrole |
Privilege | bool |
Mutable | Can create roles, default false |
inherit |
Privilege | bool |
Mutable | Inherit role privileges, default true |
replication |
Privilege | bool |
Mutable | Can replicate, default false |
bypassrls |
Privilege | bool |
Mutable | Bypass RLS, default false |
connlimit |
Privilege | int |
Mutable | Connection limit, -1 unlimited |
expire_in |
Validity | int |
Mutable | Expire N days from now (priority) |
expire_at |
Validity | string |
Mutable | Expiration date, YYYY-MM-DD format |
roles |
Role | array |
Additive | Roles array, string or object format |
parameters |
Params | object |
Mutable | Role-level parameters |
pgbouncer |
Pool | bool |
Mutable | Add to connection pool, default false |
pool_mode |
Pool | enum |
Mutable | Pool mode: transaction (default) |
pool_connlimit |
Pool | int |
Mutable | Pool user max connections |
Parameter Details
name
String, required. Username - must be unique within the cluster.
Must be a valid PostgreSQL identifier matching ^[a-z_][a-z0-9_]{0,62}$: starts with lowercase letter or underscore, contains only lowercase letters, digits, underscores, max 63 chars.
state
Enum for user operation: create or absent. Default create.
| State | Description |
|---|---|
create |
Default, create user, update if exists |
absent |
Delete user with DROP ROLE |
These system users cannot be deleted via state: absent (to prevent cluster failure):
postgres: Database superuserreplicator: Replication user (orpg_replication_username)dbuser_dba: Admin user (orpg_admin_username)dbuser_monitor: Monitor user (orpg_monitor_username)
password
String, mutable. User password - users without password can’t login via password auth.
Password can be:
| Format | Example | Description |
|---|---|---|
| Plaintext | DBUser.Meta |
Not recommended, logged to config |
| SCRAM-SHA-256 | SCRAM-SHA-256$4096:xxx$yyy:zzz |
Recommended, PG10+ default |
| MD5 hash | md5... |
Legacy compatibility |
When setting password, Pigsty temporarily disables logging to prevent leakage:
To generate SCRAM-SHA-256 hash:
comment
String, mutable. User comment, defaults to business user {name}.
Set via COMMENT ON ROLE, supports special chars (quotes auto-escaped).
login
Boolean, mutable. Can login, default true.
Setting false creates a Role rather than User - typically for permission grouping.
In PostgreSQL, CREATE USER equals CREATE ROLE ... LOGIN.
superuser
Boolean, mutable. Is superuser, default false.
Superusers have full database privileges, bypassing all permission checks.
Pigsty provides default superuser via pg_admin_username (dbuser_dba). Don’t create additional superusers unless necessary.
createdb
Boolean, mutable. Can create databases, default false.
Some applications (Gitea, Odoo, etc.) may require CREATEDB privilege for their admin users.
createrole
Boolean, mutable. Can create other roles, default false.
Users with CREATEROLE can create, modify, delete other non-superuser roles.
inherit
Boolean, mutable. Auto-inherit privileges from member roles, default true.
Setting false requires explicit SET ROLE to use member role privileges.
replication
Boolean, mutable. Can initiate streaming replication, default false.
Usually only replication users (replicator) need this. Normal users shouldn’t have it unless for logical decoding subscriptions.
bypassrls
Boolean, mutable. Bypass row-level security (RLS) policies, default false.
When enabled, user can access all rows even with RLS policies. Usually only for admins.
connlimit
Integer, mutable. Max concurrent connections, default -1 (unlimited).
Positive integer limits max simultaneous sessions for this user. Doesn’t affect superusers.
expire_in
Integer, mutable. Expire N days from current date.
This param has higher priority than expire_at. Expiration recalculated on each playbook run - good for temp users needing periodic renewal.
Generates SQL:
expire_at
String, mutable. Expiration date in YYYY-MM-DD format, or special value infinity.
Lower priority than expire_in. Use infinity for never-expiring users.
roles
Array, additive. Roles this user belongs to. Elements can be strings or objects.
Simple format - strings for role names:
Full format - objects for fine-grained control:
Object Format Parameters:
| Param | Type | Description |
|---|---|---|
name |
string | Role name (required) |
state |
enum | grant (default) or absent/revoke: control membership |
admin |
bool | true: WITH ADMIN OPTION, false: REVOKE ADMIN |
set |
bool | PG16+: true: WITH SET TRUE, false: REVOKE SET |
inherit |
bool | PG16+: true: WITH INHERIT TRUE, false: REVOKE INHERIT |
PostgreSQL 16+ New Features:
PostgreSQL 16 introduced finer-grained role membership control:
- ADMIN OPTION: Allow granting role to other users
- SET OPTION: Allow using
SET ROLEto switch to this role - INHERIT OPTION: Auto-inherit this role’s privileges
set and inherit options only work in PG16+. On earlier versions they’re ignored with warning comments.
parameters
Object, mutable. Role-level config params via ALTER ROLE ... SET. Applies to all sessions for this user.
Use special value DEFAULT (case-insensitive) to reset to PostgreSQL default:
Common role-level params:
| Parameter | Description | Example |
|---|---|---|
work_mem |
Query work memory | '64MB' |
statement_timeout |
Statement timeout | '30s' |
lock_timeout |
Lock wait timeout | '10s' |
idle_in_transaction_session_timeout |
Idle transaction timeout | '10min' |
search_path |
Schema search path | 'app,public' |
log_statement |
Log level | 'ddl' |
temp_file_limit |
Temp file size limit | '10GB' |
Query user-level params via pg_db_role_setting system view.
pgbouncer
Boolean, mutable. Add user to Pgbouncer user list, default false.
For prod users needing connection pool access, must explicitly set pgbouncer: true.
Default false prevents accidentally exposing internal users to the pool.
Users with pgbouncer: true are added to /etc/pgbouncer/userlist.txt.
pool_mode
Enum, mutable. User-level pool mode: transaction, session, or statement. Default transaction.
| Mode | Description | Use Case |
|---|---|---|
transaction |
Return connection after txn | Most OLTP apps, default |
session |
Return connection after session | Apps needing session state |
statement |
Return after each statement | Simple stateless queries |
User-level pool params are configured via /etc/pgbouncer/useropts.txt:
pool_connlimit
Integer, mutable. User-level maximum pool connections. If omitted, no user-level override is generated and Pigsty’s global pgbouncer.ini default of 100 applies. PgBouncer uses 0 to mean unlimited.
ACL System
Pigsty provides a built-in access control / ACL model. Assign these default business roles to users as required:
| Role | Privileges | Typical Use Case |
|---|---|---|
dbrole_readwrite |
Global read-write | Primary application accounts |
dbrole_readonly |
Global read-only | Read-only application access |
dbrole_admin |
DDL privileges | Application administrators and table creation |
dbrole_offline |
Independent read-only; instance scope controlled by HBA | Ad hoc users, ETL, and analytics |
dbrole_offline does not itself restrict a user to offline instances. To establish that boundary, set role: offline on the corresponding HBA rule; see Offline Role and Instance Isolation.
To redesign your own ACL system, customize:
pg_default_roles: System-wide roles and global userspg_default_privileges: Default privileges for new objectspg-init-roles.sql: Role creation SQL templatepg-init-template.sql: Privilege SQL template
Pgbouncer Users
Pgbouncer is enabled by default as connection pool middleware. Pigsty adds all users in pg_users with explicit pgbouncer: true flag to the pgbouncer user list.
Users in connection pool are listed in /etc/pgbouncer/userlist.txt:
User-level pool params are maintained in /etc/pgbouncer/useropts.txt:
When creating users, Pgbouncer user list is refreshed via online reload - doesn’t affect existing connections.
Pgbouncer runs as same dbsu as PostgreSQL (default postgres OS user). Use pgb alias to access pgbouncer admin functions.
pgbouncer_auth_query param allows dynamic query for pool user auth - convenient when you prefer not to manually manage pool users.
Related Resources
For user management operations, see User Management.
For user access privileges, see Access Control: Role System.
5 - Database
In this document, “database” refers to a logical object within a database cluster created with
CREATE DATABASE.
A PostgreSQL cluster can serve multiple databases simultaneously. In Pigsty, you can define required databases in cluster configuration.
Pigsty customizes the template1 template database - creating default schemas, installing default extensions, configuring default privileges. Newly created databases inherit these settings from template1.
You can also specify other template databases via template for instant database cloning.
By default, all business databases are 1:1 added to Pgbouncer connection pool; pg_exporter auto-discovers all business databases for in-database object monitoring.
All databases are also registered as PostgreSQL datasources in Grafana on all INFRA nodes for PGCAT dashboards.
Define Database
Business databases are defined in cluster param pg_databases, an array of database definition objects.
During cluster initialization, databases are created in definition order, so later databases can use earlier ones as templates.
Example from Pigsty demo pg-meta cluster:
Each database definition is a complex object with fields below. Only name is required:
Since Pigsty
v4.1.0, database pool fields are unified aspool_reserveandpool_connlimit; legacy aliasespool_size_reserve/pool_max_db_connare converged.
Parameter Overview
The only required field is name - a valid, unique database name within the cluster. All other params have sensible defaults.
Parameters marked “Immutable” only take effect at creation; changing them requires database recreation.
| Field | Category | Type | Attr | Description |
|---|---|---|---|---|
name |
Basic | string |
Required | Database name, must be valid and unique |
state |
Basic | enum |
Optional | State: create (default), absent, recreate |
owner |
Basic | string |
Mutable | Database owner, defaults to postgres |
comment |
Basic | string |
Mutable | Database comment |
template |
Template | string |
Immutable | Template database, default template1 |
strategy |
Template | enum |
Immutable | Clone strategy: FILE_COPY or WAL_LOG (PG15+) |
encoding |
Encoding | string |
Immutable | Character encoding, default inherited (UTF8) |
locale |
Encoding | string |
Immutable | Locale setting, default inherited (C) |
lc_collate |
Encoding | string |
Immutable | Collation rule, default inherited (C) |
lc_ctype |
Encoding | string |
Immutable | Character classification, default inherited (C) |
locale_provider |
Encoding | enum |
Immutable | Locale provider: libc, icu, builtin (PG15+) |
icu_locale |
Encoding | string |
Immutable | ICU locale rules (PG15+) |
icu_rules |
Encoding | string |
Immutable | ICU collation customization (PG16+) |
builtin_locale |
Encoding | string |
Immutable | Builtin locale rules (PG17+) |
tablespace |
Storage | string |
Mutable | Default tablespace, change triggers data migration |
is_template |
Privilege | bool |
Mutable | Mark as template database |
allowconn |
Privilege | bool |
Mutable | Allow connections, default true |
revokeconn |
Privilege | bool |
Mutable | Revoke PUBLIC CONNECT privilege |
connlimit |
Privilege | int |
Mutable | Connection limit, -1 for unlimited |
baseline |
Init | string |
Mutable | SQL baseline file path, runs on every provisioning |
schemas |
Init | (string|object)[] |
Mutable | Schema definitions to create |
extensions |
Init | (string|object)[] |
Mutable | Extension definitions to install |
parameters |
Init | object |
Mutable | Database-level parameters |
pgbouncer |
Pool | bool |
Mutable | Add to connection pool, default true |
pool_mode |
Pool | enum |
Mutable | Pool mode: transaction (default) |
pool_size |
Pool | int |
Mutable | Default pool size, default 50 |
pool_size_min |
Pool | int |
Mutable | Min pool size, default 0 |
pool_reserve |
Pool | int |
Mutable | Reserve pool size, default 30 |
pool_connlimit |
Pool | int |
Mutable | Max database connections, default 100 |
pool_auth_user |
Pool | string |
Mutable | Auth query user |
register_datasource |
Monitor | bool |
Mutable | Register to Grafana datasource, default true |
Parameter Details
name
String, required. Database name - must be unique within the cluster.
The current role does not enforce this regular expression, and SQL identifiers are double-quoted. However, the name is also used in temporary file paths and shell/SQL command assembly. For safe operation across the entire automation chain, keep it within 63 bytes, follow ^[A-Za-z_][A-Za-z0-9_$]{0,62}$, and avoid spaces, quotes, slashes, or other special characters.
state
Enum for database operation: create, absent, or recreate. Default create.
| State | Description |
|---|---|
create |
Default, create or modify database, adjust mutable params if exists |
absent |
Delete database with DROP DATABASE WITH (FORCE) |
recreate |
Drop then create, for database reset |
owner
String. Database owner, defaults to pg_dbsu (postgres) if not specified.
Target user must exist. Changing owner executes (old owner retains existing privileges):
Database owner has full control including creating schemas, tables, extensions - useful for multi-tenant scenarios.
comment
String. Database comment, defaults to business database {name}.
Set via COMMENT ON DATABASE, supports Chinese and special characters (Pigsty auto-escapes quotes). Stored in the shared-object comment catalog pg_shdescription, viewable via \l+.
template
String, immutable. Template database for creation, default template1.
PostgreSQL’s CREATE DATABASE clones the template - new database inherits all objects, extensions, schemas, permissions. Pigsty customizes template1 during cluster init, so new databases inherit these settings.
| Template | Description |
|---|---|
template1 |
Default, includes Pigsty pre-configured extensions/schemas/perms |
template0 |
Clean template, required for non-default locale providers |
| Custom database | Use existing database as template for cloning |
When using icu or builtin locale provider, must specify template: template0 since template1 locale settings can’t be overridden.
Using template0 skips monitoring extensions/schemas and default privileges - allowing fully custom database.
strategy
Enum, immutable. Clone strategy: FILE_COPY or WAL_LOG. Available PG15+.
| Strategy | Description | Use Case |
|---|---|---|
FILE_COPY |
Direct file copy with checkpoints before and after | Large templates, lower WAL volume |
WAL_LOG |
Block-by-block copy written to WAL; PG15+ default | Small templates, non-blocking |
WAL_LOG doesn’t block template connections during clone but less efficient for large templates. Ignored on PG14 and earlier.
encoding
String, immutable. Character encoding, inherits from template if unspecified (usually UTF8).
Strongly recommend UTF8 unless special requirements. Cannot be changed after creation.
locale
String, immutable. Locale setting - sets both lc_collate and lc_ctype. Inherits from template (usually C).
Determines string sort order and character classification. Use C or POSIX for best performance and cross-platform consistency; use language-specific locales (e.g., zh_CN.UTF-8) for proper language sorting.
lc_collate
String, immutable. String collation rule. Inherits from template (usually C).
Determines ORDER BY and comparison results. Common values: C (byte order, fastest), C.UTF-8, en_US.UTF-8, zh_CN.UTF-8. Cannot be changed after creation.
lc_ctype
String, immutable. Character classification rule for upper/lower case, digits, letters. Inherits from template (usually C).
Affects upper(), lower(), regex \w, etc. Cannot be changed after creation.
locale_provider
Enum, immutable. Locale implementation provider: libc, icu, or builtin. Available PG15+, default libc.
| Provider | Version | Description |
|---|---|---|
libc |
- | OS C library, traditional default, varies by system |
icu |
PG15+ | ICU library, cross-platform consistent, more langs |
builtin |
PG17+ | PostgreSQL builtin, most efficient, C/C.UTF-8 only |
Using icu or builtin requires template: template0 with corresponding icu_locale or builtin_locale.
icu_locale
String, immutable. ICU locale identifier. Available PG15+ when locale_provider: icu.
ICU identifiers follow BCP 47. Common values:
| Value | Description |
|---|---|
en-US |
US English |
en-GB |
British English |
zh-Hans |
Simplified Chinese |
zh-Hant |
Traditional Chinese |
ja-JP |
Japanese |
ko-KR |
Korean |
icu_rules
String, immutable. Custom ICU collation rules. Available PG16+.
Allows fine-tuning default sort behavior using ICU Collation Customization.
builtin_locale
String, immutable. Builtin locale provider rules. Available PG17+ when locale_provider: builtin. Values: C or C.UTF-8.
builtin provider is PG17’s new builtin implementation - faster than libc with consistent cross-platform behavior. Suitable for C/C.UTF-8 collation only.
tablespace
String, mutable. Default tablespace, default pg_default.
Changing tablespace triggers physical data migration - PostgreSQL moves all objects to new tablespace. Can take long time for large databases, use cautiously.
is_template
Boolean, mutable. Mark database as template, default false.
When true, any user with CREATEDB privilege can use this database as template for cloning. Template databases typically pre-install standard schemas, extensions, and data.
Deleting is_template: true databases: Pigsty first executes ALTER DATABASE ... IS_TEMPLATE false then drops.
allowconn
Boolean, mutable. Allow connections, default true.
Setting false completely disables connections at database level - no user (including superuser) can connect. Used for maintenance or archival purposes.
revokeconn
Boolean, mutable. Revoke PUBLIC CONNECT privilege, default false.
When true, Pigsty executes:
- Revoke PUBLIC CONNECT, regular users can’t connect
- Grant connect to replication user (
replicator) and monitor user (dbuser_monitor) - Grant connect to admin user (
dbuser_dba) and owner withWITH GRANT OPTION
Setting false restores PUBLIC CONNECT privilege.
connlimit
Integer, mutable. Max concurrent connections, default -1 (unlimited).
Positive integer limits max simultaneous sessions. Doesn’t affect superusers.
baseline
String. SQL baseline file path executed while provisioning the database.
Baseline files typically contain schema definitions, initial data, stored procedures. Path is relative to Ansible search path, usually in files/.
Whenever baseline is defined, the current role runs the file on every provisioning pass for that database, even if the database already exists. It also runs after state: recreate. Make the baseline SQL idempotent, or avoid rerunning it against an existing database.
schemas
Array, mutable (add/remove). Schema definitions to create or drop. Elements can be strings or objects.
Simple format - strings for schema names (create only):
Full format - objects for owner and drop operations:
Create uses IF NOT EXISTS; drop uses CASCADE (deletes all objects in schema).
extensions
Array, mutable (add/remove). Extension definitions to install or uninstall. Elements can be strings or objects.
Simple format - strings for extension names (install only):
Full format - objects for schema, version, and uninstall:
Installation uses IF NOT EXISTS ... CASCADE; PostgreSQL emits a NOTICE and skips an extension that already exists, while automatically installing dependencies when possible. Uninstallation uses CASCADE and deletes dependent objects.
parameters
Object, mutable. Database-level config params via ALTER DATABASE ... SET. Applies to all sessions connecting to this database.
Use special value DEFAULT (case-insensitive) to reset to PostgreSQL default:
pgbouncer
Boolean, mutable. Add database to Pgbouncer pool list, default true.
Setting false excludes database from Pgbouncer - clients can’t access via connection pool. For internal management databases or direct-connect scenarios.
pool_mode
Enum, mutable. Pgbouncer pool mode: transaction, session, or statement. Default transaction.
| Mode | Description | Use Case |
|---|---|---|
transaction |
Return connection after txn | Most OLTP apps, default |
session |
Return connection after session | Apps needing session state |
statement |
Return after each statement | Simple stateless queries |
pool_size
Integer, mutable. Pgbouncer default pool size, default 50.
Pool size is the regular backend-connection limit for this database’s pool; pool_size_min controls prewarmed connections. Adjust it for the workload.
pool_size_min
Integer, mutable. Pgbouncer minimum pool size, default 0.
Values > 0 pre-create specified backend connections for connection warming, reducing first-request latency.
pool_reserve
Integer, mutable. Pgbouncer reserve pool size, default 30.
When default pool exhausted, Pgbouncer can allocate up to pool_reserve additional connections for burst traffic.
pool_connlimit
Integer, mutable. Max connections via Pgbouncer pool, default 100.
This is Pgbouncer-level limit, independent of database’s connlimit param.
pool_auth_user
String, mutable. User for Pgbouncer auth query.
Requires pgbouncer_auth_query enabled. When set, all Pgbouncer connections to this database use specified user for auth query password verification.
register_datasource
Boolean, mutable. Register database to Grafana as PostgreSQL datasource, default true.
Set false to skip Grafana registration. For temp databases, test databases, or internal databases not needed in monitoring.
Template Inheritance
Many parameters inherit from template database if not explicitly specified. Default template is template1, whose encoding settings are determined by cluster init params:
| Cluster Param | Default | Description |
|---|---|---|
pg_encoding |
UTF8 |
Cluster encoding |
pg_locale |
C / C-UTF-8 (if supported) |
Cluster locale |
pg_lc_collate |
C / C-UTF-8 (if supported) |
Cluster collation |
pg_lc_ctype |
C / C-UTF-8 (if supported) |
Cluster ctype |
New databases fork from template1, which is customized during PG_PROVISION with extensions, schemas, and default privileges. Unless you explicitly use another template.
Deep Customization
Pigsty provides rich customization params. To customize template database, refer to:
pg_default_roles: Default predefined roles and system userspg_default_privileges: Default privileges for objects created by admin userpg_default_schemas: Default schemas to createpg_default_extensions: Default extensions to createpg_default_hba_rules: Default PostgreSQL HBA rulespgb_default_hba_rules: Default Pgbouncer HBA rules
If above configurations don’t meet your needs, use pg_init to specify custom cluster init scripts:
pg-init: Cluster init scriptpg-init-template.sql: Template customization SQLpg-init-roles.sql: Default roles SQL
Locale Providers
PostgreSQL 15+ introduced locale_provider for different locale implementations. These are immutable after creation.
Pigsty’s configure wizard selects builtin C.UTF-8/C locale provider based on PG and OS versions.
Databases inherit cluster locale by default. To specify different locale provider, you must use template0.
Using ICU provider (PG15+):
Using builtin provider (PG17+):
Provider comparison: libc (traditional, OS-dependent), icu (PG15+, cross-platform, feature-rich), builtin (PG17+, most efficient C/C.UTF-8).
Connection Pool
Pgbouncer connection pool optimizes short-connection performance, reduces contention, prevents excessive connections from overwhelming database, and provides flexibility during migrations.
Pigsty configures 1:1 connection pool for each PostgreSQL instance, running as same pg_dbsu (default postgres OS user). Pool communicates with database via /var/run/postgresql Unix socket.
Pigsty adds all databases in pg_databases to pgbouncer by default.
Set pgbouncer: false to exclude specific databases.
Pgbouncer database list and config params are defined in /etc/pgbouncer/database.txt:
When creating databases, Pgbouncer database list is refreshed via online reload - doesn’t affect existing connections.
6 - HBA Rules
Overview
HBA (Host-Based Authentication) controls “who can connect to the database, from where, and how”. See Authentication for the authentication model and default rules.
Pigsty manages HBA rules declaratively through pg_default_hba_rules and pg_hba_rules.
Pigsty renders the following config files during cluster init or HBA refresh:
| Config File | Path | Description |
|---|---|---|
| PostgreSQL HBA | /pg/data/pg_hba.conf |
PostgreSQL server HBA rules |
| PgBouncer HBA | /etc/pgbouncer/pgb_hba.conf |
Connection pool HBA rules |
HBA rules are controlled by these parameters:
| Parameter | Level | Description |
|---|---|---|
pg_default_hba_rules |
G | PostgreSQL global default HBA |
pg_hba_rules |
G/C/I | PostgreSQL cluster/instance add |
pgb_default_hba_rules |
G | PgBouncer global default HBA |
pgb_hba_rules |
G/C/I | PgBouncer cluster/instance add |
Rule features:
- Role filtering: Rules support
rolefield, auto-filter based on instance’spg_role - Order sorting: Rules support
orderfield, controls position in final config file - Two syntaxes: Supports alias form (simplified) and raw form (direct HBA text)
Refresh HBA
After modifying config, re-render config files and reload services:
Script executes the following playbook:
PostgreSQL only: ./pgsql.yml -l <cls> -t pg_hba,pg_reload -e pg_reload=true
PgBouncer only: ./pgsql.yml -l <cls> -t pgbouncer_hba,pgbouncer_reload
Don’t directly edit /pg/data/pg_hba.conf or /etc/pgbouncer/pgb_hba.conf - they’ll be overwritten on next playbook run.
All changes should be made in pigsty.yml, then execute bin/pgsql-hba to refresh.
Parameter Details
pg_default_hba_rules
PostgreSQL global default HBA rule list, usually defined in all.vars, provides base access control for all clusters.
- Type:
rule[], Level: Global (G)
pg_hba_rules
PostgreSQL cluster/instance-level additional HBA rules, can override at cluster or instance level, merged with default rules and sorted by order.
- Type:
rule[], Level: Global/Cluster/Instance (G/C/I), Default:[]
pgb_default_hba_rules
PgBouncer global default HBA rule list, usually defined in all.vars.
- Type:
rule[], Level: Global (G)
pgb_hba_rules
PgBouncer cluster/instance-level additional HBA rules.
- Type:
rule[], Level: Global/Cluster/Instance (G/C/I), Default:[]
Note: PgBouncer HBA does not support
db: replication.
Rule Fields
Each HBA rule is a YAML dict supporting these fields:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
user |
string | No | all |
Username, supports all, placeholders, +rolename |
db |
string | No | all |
Database name, supports all, replication, db name |
addr |
string | Yes* | - | Address alias or CIDR, see Address Aliases |
auth |
string | No | pwd |
Auth method alias, see Auth Methods |
title |
string | No | - | Rule description, rendered as comment in config |
role |
string | No | common |
Instance role filter, see Role Filtering |
order |
int | No | 1000 |
Sort weight, lower first, see Order Sorting |
rules |
list | Yes* | - | Raw HBA text lines, mutually exclusive with addr |
Either
addrorrulesmust be specified. Userulesto write raw HBA format directly.
Address Aliases
Pigsty provides address aliases to simplify HBA rule writing:
| Alias | Expands To | Description |
|---|---|---|
local |
Unix socket | Local Unix socket |
localhost |
Unix socket + 127.0.0.1/32 + ::1/128 |
Loopback addresses |
admin |
${admin_ip}/32 |
Admin IP address |
infra |
All infra group node IPs | Infrastructure nodes |
cluster |
All current cluster member IPs | Same cluster instances |
intra / intranet |
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 |
Intranet CIDRs |
world / all |
0.0.0.0/0 + ::/0 |
Any address (IPv4 + IPv6) |
<CIDR> |
Direct use | e.g., 192.168.1.0/24 |
Intranet CIDRs can be customized via node_firewall_intranet:
Auth Methods
Pigsty provides auth method aliases for simplified config:
| Alias | Actual Method | Connection Type | Description |
|---|---|---|---|
pwd |
scram-sha-256 or md5 |
host |
Auto-select based on pg_pwd_enc |
ssl |
scram-sha-256 or md5 |
hostssl |
Force SSL + password |
ssl-sha |
scram-sha-256 |
hostssl |
Force SSL + SCRAM-SHA-256 |
ssl-md5 |
md5 |
hostssl |
Force SSL + MD5 |
cert |
cert |
hostssl |
Client certificate auth |
trust |
trust |
host |
Unconditional trust (dangerous) |
deny / reject |
reject |
host |
Reject connection |
ident |
ident |
host |
OS user mapping (PostgreSQL) |
peer |
peer |
local |
OS user mapping (PgBouncer/local) |
pg_pwd_encdefaults toscram-sha-256, can be set tomd5for legacy client compatibility.
User Variables
HBA rules support these user placeholders, auto-replaced with actual usernames during rendering:
| Placeholder | Default | Corresponding Param |
|---|---|---|
${dbsu} |
postgres |
pg_dbsu |
${repl} |
replicator |
pg_replication_username |
${monitor} |
dbuser_monitor |
pg_monitor_username |
${admin} |
dbuser_dba |
pg_admin_username |
Role Filtering
The role field in HBA rules controls which instances the rule applies to:
| Role | Description |
|---|---|
common |
Default, applies to all instances |
primary |
Primary instance only |
replica |
Replica instance only |
offline |
Offline instance only (pg_role: offline or pg_offline_query: true) |
standby |
Standby instance |
delayed |
Delayed replica instance |
Role filtering matches based on instance’s pg_role variable. Non-matching rules are commented out (prefixed with #).
Order Sorting
PostgreSQL HBA is first-match-wins, rule order is critical. Pigsty controls rule rendering order via the order field.
Order Interval Convention
| Interval | Usage |
|---|---|
0 - 99 |
User high-priority rules (before all defaults) |
100 - 650 |
Default rule zone (spaced by 50 for insertion) |
1000+ |
User rule default (rules without order) |
PostgreSQL Default Rules Order
| Order | Rule Description |
|---|---|
| 100 | dbsu local ident |
| 150 | dbsu replication local |
| 200 | replicator localhost |
| 250 | replicator intra replication |
| 300 | replicator intra postgres |
| 350 | monitor localhost |
| 400 | monitor infra |
| 450 | admin infra ssl |
| 500 | admin world ssl |
| 550 | dbrole_readonly localhost |
| 600 | dbrole_readonly intra |
| 650 | dbrole_offline intra |
PgBouncer Default Rules Order
| Order | Rule Description |
|---|---|
| 100 | dbsu local peer |
| 150 | all localhost pwd |
| 200 | monitor pgbouncer intra |
| 250 | monitor world deny |
| 300 | admin intra pwd |
| 350 | admin world deny |
| 400 | all intra pwd |
Syntax Examples
Alias Form: Using Pigsty simplified syntax
Rendered result:
Raw Form: Using PostgreSQL HBA syntax directly
Rendered result:
Common Scenarios
Blacklist IP: Use order: 0 to ensure first match
Whitelist App Server: High priority for specific IP
Admin Force Certificate: Override default SSL password auth
Offline Instance Dedicated Network: Only on offline instances
Restrict Access by Database: Sensitive databases limited to specific networks
PgBouncer Dedicated Rules: Note no db: replication support
Complete Cluster Example
Verification & Troubleshooting
View Current HBA Rules
Test Connection Auth
Common Issues
| Error Message | Possible Cause | Solution |
|---|---|---|
no pg_hba.conf entry for host... |
No matching HBA rule | Add corresponding rule and refresh |
password authentication failed |
Wrong password or enc | Check password and pg_pwd_enc |
| Rule not taking effect | Not refreshed or order | Run bin/pgsql-hba, check order |
Important Notes
- Order sensitive: PostgreSQL HBA is first-match-wins, use
orderwisely - Role matching: Ensure
rolefield matches target instance’spg_role - Address format: CIDR must be correct, e.g.,
10.0.0.0/8not10.0.0.0/255.0.0.0 - PgBouncer limitation: Does not support
db: replication - TLS prerequisite:
sslandcertrequire server-side TLS; clients must still useverify-fullto authenticate the server - Test first: Validate in test environment before modifying HBA
- Refresh on scale: Rules using
addr: clusterneed refresh after cluster membership changes
Related Documentation
- HBA Management: Refresh, verification, and troubleshooting
- User Config: User and role configuration
- Access Control: Role system and permission model
- Authentication: HBA, SCRAM, client certificates, and default rules
- Encrypted Communication: TLS and server certificate verification
7 - Access Control
Access control combines roles, object privileges, database ACLs, and HBA. This page covers configuration parameters; see Access Control Concepts for design and boundaries.
Pigsty provides a compact ACL model described by these parameters:
pg_default_roles: system roles and system users.pg_users: application users and roles.pg_default_privileges: default privileges on objects created by managed administrators and owners.pg_revoke_public,pg_default_schemas, andpg_default_extensions: default behavior fortemplate1.
Manage these parameters together with HBA and database definitions to produce reproducible access-control configuration.
Default Role System (pg_default_roles)
The defaults contain four business roles and four system users:
| Name | Type | Description |
|---|---|---|
dbrole_readonly |
NOLOGIN |
Shared read-only role with SELECT and USAGE |
dbrole_readwrite |
NOLOGIN |
Inherits read-only and adds INSERT, UPDATE, and DELETE |
dbrole_admin |
NOLOGIN |
Inherits pg_monitor and read-write; can create objects and triggers |
dbrole_offline |
NOLOGIN |
Independent read-only role; instance scope must be restricted explicitly through HBA |
postgres |
User | System superuser; same name as pg_dbsu |
replicator |
User | Streaming replication and backup; inherits monitoring and read-only privileges |
dbuser_dba |
User | Primary administration account, also synchronized to PgBouncer |
dbuser_monitor |
User | Monitoring account with pg_monitor; records slow SQL by default |
These definitions live in pg_default_roles. The parameter is a complete list. When customizing it, copy and retain the required default roles and system users, then add new roles in dependency order. If a role name changes, update references in HBA, default privileges, and scripts.
Default Users and Credential Parameters
These parameters control system-user names and passwords:
| Parameter | Default | Purpose |
|---|---|---|
pg_dbsu |
postgres |
Database and OS superuser |
pg_dbsu_password |
Empty string | dbsu password, disabled by default |
pg_replication_username |
replicator |
Replication user name |
pg_replication_password |
DBUser.Replicator |
Replication password |
pg_admin_username |
dbuser_dba |
Administrator user name |
pg_admin_password |
DBUser.DBA |
Administrator password |
pg_monitor_username |
dbuser_monitor |
Monitoring user |
pg_monitor_password |
DBUser.Monitor |
Monitoring password |
After changing these parameters, update the corresponding user definitions in pg_default_roles so user names and role attributes remain consistent.
Application Roles and Grants (pg_users)
Declare application users with pg_users; see User Configuration for field details. The roles field grants business roles.
Example read-only and read-write users:
Application users inherit default object privileges through dbrole_*. Database CONNECT privileges and pg_hba_rules continue to control which databases and sources can connect.
For finer ACLs, use standard GRANT and REVOKE in baseline SQL or a later playbook, and include those additional grants in reviews.
Default Privilege Template (pg_default_privileges)
pg_default_privileges applies to pg_dbsu, pg_admin_username, dbrole_admin, and every declared database owner. The default template is:
Objects created by these identities receive the corresponding privileges automatically. Other object creators need their own
ALTER DEFAULT PRIVILEGESconfiguration.
Additional notes:
pg_revoke_publicdefaults totrue, revokingCREATEfromPUBLICon databases and thepublicschema.pg_default_schemasandpg_default_extensionscontrol schemas and extensions created intemplate1/postgres, usually for monitoring objects such as themonitorschema andpg_stat_statements.
Common Scenarios
Read-only Account for a Partner
This adds an HBA rule allowing the partner to reach analytics over TLS from the specified CIDR. pg_hba_rules does not remove broader default rules. If the account must reach only this database, also narrow the default HBA policy and configure database CONNECT privileges.
DDL for an Application Administrator
app_admininherits DDL privileges fromdbrole_admin. To apply the default privileges configured fordbrole_adminto new objects, runSET ROLE dbrole_adminfirst. Ifapp_adminis a declared database owner, it can also create objects directly as that owner.
Custom Default Privileges
This parameter replaces the complete default privilege list. Referenced roles must already exist. Changes affect only objects created afterward; grant privileges separately on existing objects.
Integration with Other Components
- HBA rules: use
pg_hba_rulesto bind roles, databases, and sources. To restrictdbrole_offline, setrole: offlineon its rule. - PgBouncer: users with
pgbouncer: trueare written touserlist.txt;pool_modeandpool_connlimitcontrol pool-level quotas. - Database monitoring:
dbuser_monitorreceives privileges frompg_default_roles. When adding another monitoring user, grantpg_monitorand check access to themonitorschema.
These parameters can be versioned with the inventory. Continue to review effective privileges through PostgreSQL catalogs.
Related Documentation
- Access Control Concepts: roles, default privileges, and isolation boundaries
- Authentication: HBA, SCRAM, and client certificates
- User Configuration: user and role fields
- HBA Configuration: connection-entry rules
8 - Parameters
PostgreSQL parameters can be configured at multiple levels with different scopes and precedence. Pigsty supports four configuration levels, from global to local:
| Level | Scope | Configuration Method | Storage Location |
|---|---|---|---|
| Cluster | All instances in cluster | Patroni DCS / Tuning Templates | etcd + postgresql.conf |
| Instance | Single PG instance | pg_parameters / ALTER SYSTEM |
postgresql.auto.conf |
| Database | All sessions in a DB | pg_databases[].parameters |
pg_db_role_setting |
| User | All sessions of a user | pg_users[].parameters |
pg_db_role_setting |
Priority from low to high: Cluster < Instance < Database < User < Session (SET command).
Higher priority settings override lower ones.
For complete PostgreSQL parameter documentation, see PostgreSQL Docs: Server Configuration.
Cluster Level
Cluster-level parameters are shared across all instances (primary and replicas) in a PostgreSQL cluster. In Pigsty, cluster parameters are managed via Patroni and stored in DCS (etcd by default).
Pigsty provides four pre-configured Patroni tuning templates optimized for different workloads, specified via pg_conf:
| Template | Use Case | Characteristics |
|---|---|---|
oltp.yml |
OLTP transactions | Low latency, high concurrency (default) |
olap.yml |
OLAP analytics | Large queries, high throughput |
crit.yml |
Critical/Financial | Max durability, safety over perf |
tiny.yml |
Tiny instances | Resource-constrained, dev/test |
Template files are located in roles/pgsql/templates/ and contain auto-calculated values based on hardware specs.
Templates are rendered to /etc/patroni/patroni.yml during cluster initialization. See Tuning Templates for details.
Before cluster creation, you can adjust these templates to modify initial parameters. Once initialized, parameter changes should be made via Patroni’s configuration management.
Patroni DCS Config
Patroni stores cluster config in DCS (etcd by default), ensuring consistent configuration across all members.
Storage Structure:
Rendering Flow:
- Init: Template (e.g.,
oltp.yml) rendered via Jinja2 to/etc/patroni/patroni.yml - Start: Patroni reads local config, writes PostgreSQL parameters to DCS
- Runtime: Patroni periodically syncs DCS config to local PostgreSQL
Local Cache:
Each Patroni instance caches DCS config locally at /pg/conf/<instance>.yml:
- On start: Load from DCS, cache locally
- Runtime: Periodically sync DCS to local cache
- DCS unavailable: Continue with local cache (no failover possible)
Config File Hierarchy
Patroni renders DCS config to local PostgreSQL config files:
Load Order (priority low to high):
postgresql.conf: Dynamically generated by Patroni with DCS cluster paramspostgresql.base.conf: Loaded viainclude, static base configpostgresql.auto.conf: Auto-loaded by PostgreSQL, instance overrides
Since postgresql.auto.conf loads last, its parameters override earlier files.
Instance Level
Instance-level parameters apply only to a single PostgreSQL instance, overriding cluster-level config.
These are written to postgresql.auto.conf, which loads last and can override any cluster parameter.
This is a powerful technique for setting instance-specific values:
- Set
hot_standby_feedback = onon replicas - Adjust
work_memormaintenance_work_memfor specific instances - Set
recovery_min_apply_delayfor delayed replicas
Using pg_parameters
In Pigsty config, use pg_parameters to define instance-level parameters:
Use ./pgsql.yml -l <cls> -t pg_param to apply parameters, which renders to postgresql.auto.conf.
Override Hierarchy
pg_parameters can be defined at different Ansible config levels, priority low to high:
Using ALTER SYSTEM
You can also modify instance parameters at runtime via ALTER SYSTEM:
ALTER SYSTEM writes to postgresql.auto.conf.
Note: In Pigsty-managed clusters,
postgresql.auto.confis managed by Ansible viapg_parameters. ManualALTER SYSTEMchanges may be overwritten on next playbook run. Usepg_parametersinpigsty.ymlfor persistent instance-level params.
List-Type Parameters
PostgreSQL has special parameters accepting comma-separated lists. In YAML config, the entire value must be quoted, otherwise YAML parses it as an array:
Pigsty auto-detects these list parameters and renders them without outer quotes:
| Parameter | Description | Example Value |
|---|---|---|
shared_preload_libraries |
Preload shared libs | 'timescaledb, pg_stat_statements' |
search_path |
Schema search path | '"$user", public, app' |
local_preload_libraries |
Local preload libs | 'auto_explain' |
session_preload_libraries |
Session preload libs | 'pg_hint_plan' |
log_destination |
Log output targets | 'csvlog, stderr' |
unix_socket_directories |
Unix socket dirs | '/var/run/postgresql, /tmp' |
temp_tablespaces |
Temp tablespaces | 'ssd_space, hdd_space' |
debug_io_direct |
Direct I/O mode (PG16+) | 'data, wal' |
Rendering Example:
Database Level
Database-level parameters apply to all sessions connected to a specific database.
Implemented via ALTER DATABASE ... SET, stored in pg_db_role_setting.
Configuration
Use the parameters field in pg_databases:
Like instance-level params, list-type values must be quoted in YAML.
Rendering Rules
Database params are set via ALTER DATABASE ... SET. Pigsty auto-selects correct syntax:
List-type params (search_path, temp_tablespaces, local_preload_libraries, session_preload_libraries, log_destination) without outer quotes:
Scalar params with quoted values:
Note: While
log_destinationis in the database whitelist, itscontextissighup, so it cannot take effect at database level. Configure it at instance level (pg_parameters).
View Database Params
Manual Management
User Level
User-level parameters apply to all sessions of a specific database user.
Implemented via ALTER USER ... SET, also stored in pg_db_role_setting.
Configuration
Use the parameters field in pg_users or pg_default_roles:
Rendering Rules
Same as database-level:
List-type params (search_path, temp_tablespaces, local_preload_libraries, session_preload_libraries) without outer quotes:
Scalar params with quoted values:
DEFAULT Value
Use DEFAULT (case-insensitive) to reset a parameter to PostgreSQL default:
View User Params
Manual Management
Priority
When the same parameter is set at multiple levels, PostgreSQL applies this priority (low to high):
Database vs User Priority:
When a user connects to a specific database and the same parameter is set at both levels, PostgreSQL uses the user-level parameter since it has higher priority.
Example:
analystconnecting toanalytics:work_mem = 512MB(user takes precedence)- Other users connecting to
analytics:work_mem = 256MB(database applies) analystconnecting to other DBs:work_mem = 512MB(user applies)