Getting Started

PG Exporter is an advanced PostgreSQL and pgBouncer metrics exporter for Prometheus. This guide will help you get up and running quickly.

Prerequisites

Before you begin, ensure you have:

  • PostgreSQL 10-19+ or pgBouncer 1.8-1.25+ instance to monitor
  • PostgreSQL 9.1-9.6 legacy instances require the legacy/ config bundle
  • A user account with appropriate permissions for monitoring
  • Prometheus Compatible System (for metrics scraping)
  • Basic understanding of PostgreSQL connection strings

Compatibility

  • The default config supports PostgreSQL 10-19+; PostgreSQL 9.1-9.6 requires the legacy/ config bundle
  • pgBouncer 1.8-1.25+ is supported

Design Rationale

pg_exporter follows three core runtime principles:

  • Local-first connectivity: if you do not pass --url or PG_EXPORTER_URL, it falls back to postgresql:///?sslmode=disable
  • Declarative collection: all business metrics come from YAML collectors, and runtime planning picks branches by version, role, and tags
  • Keep serving under failure: non-blocking startup is the default, so HTTP endpoints come up first while the target database is temporarily unavailable, then recover health in the background

Quick Start

The fastest way to get started with PG Exporter:

# Example: install the Linux amd64 release tarball; replace the platform suffix if needed
VERSION=$(curl -fsSL https://api.github.com/repos/pgsty/pg_exporter/releases/latest | sed -n 's/.*"tag_name": "v\([^"]*\)".*/\1/p')
wget "https://github.com/pgsty/pg_exporter/releases/download/v${VERSION}/pg_exporter-${VERSION}.linux-amd64.tar.gz"
tar -xf "pg_exporter-${VERSION}.linux-amd64.tar.gz"
sudo install "pg_exporter-${VERSION}.linux-amd64/pg_exporter" /usr/bin/
sudo install "pg_exporter-${VERSION}.linux-amd64/pg_exporter.yml" /etc/pg_exporter.yml

# Run with the local-first default URL
pg_exporter

# Or point to a PostgreSQL / pgBouncer target explicitly
PG_EXPORTER_URL='postgres://user:pass@localhost:5432/postgres' pg_exporter

# Verify metrics are available
curl http://localhost:9630/metrics

Understanding the Basics

Connection String

PG Exporter uses standard PostgreSQL connection URLs:

postgres://[user][:password]@[host][:port]/[database][?param=value]

Examples:

  • Default fallback URL when nothing is specified: postgresql:///?sslmode=disable
  • Local PostgreSQL: postgres:///postgres
  • Remote with auth: postgres://monitor:password@db.example.com:5432/postgres
  • With SSL: postgres://user:pass@host/db?sslmode=require
  • pgBouncer: postgres://pgbouncer:password@localhost:6432/pgbouncer

URL source priority from high to low:

  1. --url
  2. PG_EXPORTER_URL
  3. PGURL
  4. PG_EXPORTER_URL_FILE
  5. Default postgresql:///?sslmode=disable

Built-in Metrics

PG Exporter provides 4 core built-in metrics out of the box:

MetricTypeDescription
pg_upGauge1 if exporter can connect to PostgreSQL, 0 otherwise
pg_versionGaugePostgreSQL server version number
pg_in_recoveryGauge1 if server is in recovery mode (replica), 0 if primary
pg_exporter_build_infoGaugeExporter version and build information

The exporter also exposes pg_exporter_* self-monitoring metrics by default. You can disable them with --disable-intro.

Configuration File

All other metrics (600+) are defined in the pg_exporter.yml configuration file. By default, PG Exporter looks for this file in:

  1. Path specified by --config flag
  2. Path in PG_EXPORTER_CONFIG environment variable
  3. Current directory (./pg_exporter.yml)
  4. System config (/etc/pg_exporter.yml or /etc/pg_exporter/)

Your First Monitoring Setup

Step 1: Create a Monitoring User

Create a dedicated PostgreSQL user for monitoring:

-- Create monitoring user
CREATE USER pg_monitor WITH PASSWORD 'secure_password';

-- Grant necessary permissions
GRANT pg_monitor TO pg_monitor;
GRANT CONNECT ON DATABASE postgres TO pg_monitor;

-- For PostgreSQL 10+, pg_monitor role provides read access to monitoring views
-- For older versions, you may need additional grants

Step 2: Test Connection

Verify the exporter can connect to your database:

# Set connection URL
export PG_EXPORTER_URL='postgres://pg_monitor:secure_password@localhost:5432/postgres'

# Run in dry-run mode to test configuration
pg_exporter --dry-run

Step 3: Run the Exporter

Start PG Exporter:

# Run with default settings
pg_exporter

# Or with custom flags
pg_exporter \
  --url='postgres://pg_monitor:secure_password@localhost:5432/postgres' \
  --web.listen-address=':9630' \
  --log.level=info

Step 4: Configure Prometheus

Add PG Exporter as a target in your prometheus.yml:

scrape_configs:
  - job_name: 'postgresql'
    static_configs:
      - targets: ['localhost:9630']
        labels:
          instance: 'postgres-primary'

Step 5: Verify Metrics

Check that metrics are being collected:

# View raw metrics
curl http://localhost:9630/metrics | grep pg_

# Check exporter statistics
curl http://localhost:9630/stat

# Review current query planning
curl http://localhost:9630/explain

Auto-Discovery Mode

PG Exporter can automatically discover and monitor all databases in a PostgreSQL instance:

# Enable auto-discovery (default behavior)
pg_exporter --auto-discovery

# Exclude specific databases
pg_exporter --auto-discovery \
  --exclude-database="template0,template1,postgres"

# Include only specific databases
pg_exporter --auto-discovery \
  --include-database="app_db,analytics_db"

When auto-discovery is enabled:

  • Cluster-level metrics (1xx-5xx) are collected once per instance
  • Database-level metrics (6xx-8xx) are collected for each discovered database
  • Metrics are labeled with datname to distinguish between databases

Monitoring pgBouncer

To monitor pgBouncer instead of PostgreSQL:

# Connect to pgBouncer admin database
PG_EXPORTER_URL='postgres://pgbouncer:password@localhost:6432/pgbouncer' \
pg_exporter --config=/etc/pg_exporter.yml

The exporter automatically detects pgBouncer and:

  • Uses pgbouncer namespace for metrics
  • Executes pgBouncer-specific collectors (9xx series)
  • Provides pgBouncer-specific health checks

Using Docker

Run PG Exporter in a container:

docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -e PG_EXPORTER_URL="postgres://user:pass@host.docker.internal:5432/postgres" \
  pgsty/pg_exporter:latest

With custom configuration:

docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -v /path/to/pg_exporter.yml:/etc/pg_exporter.yml \
  -e PG_EXPORTER_URL="postgres://user:pass@db:5432/postgres" \
  pgsty/pg_exporter:latest

Health Checks

PG Exporter provides health check endpoints for load balancers and orchestrators:

# Basic health check
curl http://localhost:9630/up
# Returns: 200 if connected, 503 if not

# Primary detection
curl http://localhost:9630/primary
# Returns: 200 if primary, 404 if replica, 503 if unknown

# Replica detection
curl http://localhost:9630/replica
# Returns: 200 if replica, 404 if primary, 503 if unknown

Troubleshooting

Connection Issues

# Test with detailed logging
pg_exporter --log.level=debug --dry-run

# Check server planning
pg_exporter --explain

Permission Errors

Ensure the monitoring user has necessary permissions:

-- Check current permissions
SELECT * FROM pg_roles WHERE rolname = 'pg_monitor';

-- Grant additional permissions if needed
GRANT USAGE ON SCHEMA pg_catalog TO pg_monitor;
GRANT SELECT ON ALL TABLES IN SCHEMA pg_catalog TO pg_monitor;

Slow Scrapes

If scrapes are timing out:

  1. Check slow queries: curl http://localhost:9630/stat
  2. Adjust collector timeouts in configuration
  3. Use caching for expensive queries (set ttl in collector config)
  4. Disable expensive collectors if not needed

Next Steps


Last Modified 2026-07-01: update pg_exporter 1.3 docs (c6c5ba9)