Production deployment — connection & credentials, systemd / Docker / Kubernetes, auto-discovery and alerting
Use this page to deploy pg_exporter in production.
It describes process arguments, environment variables, monitoring users, credentials, and deployment with systemd, Docker, or Kubernetes.
It also describes pgBouncer monitoring, auto-discovery, Prometheus scrapes, and alerts.
The exporter reads process configuration from two sources. Command-line arguments take precedence:
Command-line arguments (--url, --config, …)
Environment variables (every flag has a corresponding PG_EXPORTER_* variable)
YAML collector definitions control metric collection.
The default file is /etc/pg_exporter.yml. You can also use a configuration directory.
See the Configuration reference.
Flags:
-h, --[no-]help Show context-sensitive help(also try --help-long and --help-man).
-u, --url=URL postgres target url
-c, --config=CONFIG path to config dir or file
--web.listen-address=:9630 ...
Addresses on which to expose metrics and web interface. Repeatable for multiple addresses. Examples: `:9100` or `[::1]:9100`for http, `vsock://:9100`for vsock
--web.config.file="" Path to configuration file that can enable TLS or authentication. See: https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md
-l, --label="" constant labels: comma separated list of label=value pair ($PG_EXPORTER_LABEL) -t, --tag="" tags, comma separated list of server tag ($PG_EXPORTER_TAG) -C, --[no-]disable-cache force not using cache ($PG_EXPORTER_DISABLE_CACHE) -m, --[no-]disable-intro disable internal/exporter self-monitoring metrics (only expose query metrics)($PG_EXPORTER_DISABLE_INTRO) -a, --[no-]auto-discovery automatically scrape all databases on the target server ($PG_EXPORTER_AUTO_DISCOVERY) -x, --exclude-database="template0,template1,postgres" excluded databases when auto-discovery is enabled ($PG_EXPORTER_EXCLUDE_DATABASE) -i, --include-database="" included databases when auto-discovery is enabled ($PG_EXPORTER_INCLUDE_DATABASE) -n, --namespace="" prefix of built-in metrics, (pg|pgbouncer) by default ($PG_EXPORTER_NAMESPACE) -f, --[no-]fail-fast fail fast instead of waiting during start-up ($PG_EXPORTER_FAIL_FAST) -T, --connect-timeout=100 connect timeout in ms, 100 by default ($PG_EXPORTER_CONNECT_TIMEOUT) -P, --web.telemetry-path="/metrics" URL path under which to expose metrics ($PG_EXPORTER_TELEMETRY_PATH) -D, --[no-]dry-run dry run and print raw configs
-E, --[no-]explain explain server planned queries
--log.level="info" log level: debug|info|warn|error
--log.format="logfmt" log format: logfmt|json
--[no-]version Show application version.
These behaviors affect deployment:
Startup policy: startup is non-blocking by default. If the database is unreachable, HTTP endpoints still start. A background probe retries until recovery. To fail when the database is unreachable, set --fail-fast. For example, use this option when systemd or an orchestrator controls restarts.
Telemetry path validation: from v1.4.0, startup validates --web.telemetry-path. Empty paths, conflicts with built-in endpoints, and non-canonical paths such as //metrics fail immediately with an error. Non-canonical paths cannot match requests.
Connection URL Sources
The exporter uses the first non-empty connection string from this list:
--url / -u command-line argument
PG_EXPORTER_URL environment variable
PGURL environment variable
Content of the file pointed to by PG_EXPORTER_URL_FILE (fits container Secret mounts)
If the URL omits sslmode, the exporter appends sslmode=disable.
At startup, it also clears libpq service-file environment variables, such as PGSERVICE / PGSERVICEFILE, and logs this action.
Service files can override an explicit connection target.
Clearing these variables ensures that the exporter connects to the URL shown in the log.
Monitoring User and Credentials
Create the Monitoring User
CREATEROLEmonitorWITHLOGINPASSWORD'S3cret'CONNECTIONLIMIT5;GRANTpg_monitorTOmonitor;-- built-in monitoring role (PostgreSQL 10+), covers all default collectors
Keep CONNECTION LIMIT to prevent connection exhaustion if the configuration is incorrect.
The exporter normally uses one to a few connections. With auto-discovery, it uses one connection per database.
Manage Passwords with .pgpass
Remove the password from the URL. Use libpq’s .pgpass file to supply it:
# Create as the OS user that runs the exporterecho"localhost:5432:*:monitor:S3cret" > ~/.pgpass
chmod 600 ~/.pgpass
# URL without passwordPG_EXPORTER_URL='postgres://monitor@localhost:5432/postgres'
RPM/DEB package installs
Packaged services run as the prometheus system user.
From v1.4.0, its HOME is /var/lib/prometheus. Libpq looks for ~/.pgpass there.
The package does not create this directory. Before you use .pgpass, run:
install -d -o prometheus -g prometheus /var/lib/prometheus
The HTTP port provides /metrics and the management endpoints /reload, /explain, and /stat.
Anyone with access to the port can read configuration and runtime state, or start a reload.
On a shared network, enable TLS / Basic Auth with --web.config.file (exporter-toolkit web configuration).
You can also restrict access through a firewall or reverse proxy.
Systemd Deployment (RPM/DEB packages)
RPM/DEB packages include a service unit and an environment file.
After installation, edit the environment file and start the service:
# /usr/lib/systemd/system/pg_exporter.service[Unit]Description=Prometheus exporter for PostgreSQL/Pgbouncer server metricsDocumentation=https://pigsty.io/docs/pg_exporterAfter=network.target[Service]EnvironmentFile=-/etc/default/pg_exporterUser=prometheusExecStart=/usr/bin/pg_exporter $PG_EXPORTER_OPTSRestart=on-failure[Install]WantedBy=multi-user.target
Each command-line flag has an environment variable. Add the variables you need, such as PG_EXPORTER_DISABLE_INTRO.
The file uses the noreplace package option. Upgrades do not overwrite your changes.
Common operations:
sudo systemctl enable --now pg_exporter # start and enable at bootsudo systemctl status pg_exporter # check statusjournalctl -u pg_exporter -f # follow logscurl -X POST localhost:9630/reload # hot-reload collector config (no restart)
The official image is built from scratch. It contains no system CA certificates.
To connect to remote PostgreSQL with sslmode=verify-ca / verify-full, mount a CA certificate and set sslrootcert to its path.
Without the certificate, TLS verification cannot complete.
To keep the connection string out of environment variables, set PG_EXPORTER_URL_FILE to a Secret-mounted file.
Auto-Discovery
Auto-discovery is enabled by default.
It lets one exporter instance monitor every database in the target PostgreSQL instance:
pg_exporter --auto-discovery \
--exclude-database="template0,template1,postgres"\ # default exclusion list --include-database=""# set to switch to allowlist mode
Behavior:
Cluster-level collectors (tags: [cluster]) run once on the primary connection
Database-level collectors run on every discovered database, with metrics distinguished by the datname label
Newly created / dropped databases are picked up / removed in subsequent planning cycles
Monitoring pgBouncer
Set the database name in the URL to pgbouncer. This name activates pgBouncer mode:
In pgBouncer mode, the exporter uses the pgbouncer metric prefix.
It runs only pgBouncer collectors, such as SHOW STATS / SHOW POOLS.
Usually, you run one exporter for PostgreSQL and another for pgBouncer. Give each exporter a different port.
Set the scrape interval equal to or greater than the common collector ttl.
Most collectors in the default bundle use 10 seconds.
More frequent scrapes return cached results until the TTL expires.
Alert Rules
The following rules use available metrics:
groups:- name:pg_exporterrules:# Exporter process unreachable- alert:PgExporterDownexpr:up{job="postgresql"} == 0for:1mlabels:{severity:critical }annotations:summary:"pg_exporter down ({{ $labels.instance }})"# Exporter alive but cannot reach the database- alert:PostgreSQLDownexpr:pg_up == 0for:1mlabels:{severity:critical }annotations:summary:"PostgreSQL connection failed ({{ $labels.instance }})"# Overall scrape duration abnormal (unit: seconds)- alert:PgExporterSlowScrapeexpr:pg_exporter_scrape_duration > 10for:5mlabels:{severity:warning }annotations:summary:"pg_exporter slow scrape ({{ $labels.instance }})"# A specific collector keeps failing (locate by datname/query)- alert:PgExporterQueryErrorexpr:increase(pg_exporter_query_scrape_error_count[10m]) > 0for:10mlabels:{severity:warning }annotations:summary:"Collector {{ $labels.query }} keeps failing on {{ $labels.datname }}"
Role-Based Traffic Routing
Use /primary, /replica, and /read as health probes for HAProxy or similar load balancers.
These endpoints support primary/replica routing to separate read and write traffic.
For endpoint behavior and a complete HAProxy example, see the API Reference.
Open-source Nginx does not support active HTTP health checks outside the traffic connection.
The health_check directive requires NGINX Plus.
To route PostgreSQL traffic by role, use HAProxy or a solution such as Patroni + vip-manager.