This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

PG Exporter 1.4 Documentation

Advanced PostgreSQL & pgBouncer Metrics Exporter for Prometheus

The ultimate monitoring experience for PostgreSQL with 600+ metrics, declarative configuration, and dynamic planning capabilities.

Get Started | GitHub | Live Demo


Features

FeatureDescription
Comprehensive Metrics600+ metrics covering nearly every statistics view of PostgreSQL (10-19+) and pgBouncer (1.8-1.25+)
Declarative CollectorsEvery metric comes from a YAML collector definition — a SQL query plus execution conditions; add, change, or remove metrics without touching code
Dynamic PlanningEach collector branch is admitted per target based on version, primary/replica role, installed extensions, and tags
Auto-DiscoveryAutomatically discovers and scrapes every database in an instance, distinguished by the datname label
Health Check APIs/up, /primary, /replica endpoints serve directly as load-balancer probes for primary/replica traffic routing
Smart CachingPer-collector TTL caching decouples scrape frequency from query frequency — probe and scrape storms never reach the database
Snapshot HistogramsHISTOGRAM column type aggregates SQL snapshots into classic Prometheus histogram distributions
Extension AwareNative support for pg_stat_statements, pg_wait_sampling, citus, and timescaledb
Production ReadyBattle-tested in real-world environments across 12K+ cores for 6+ years

Version Info

  • Current stable release: v1.4.1
  • Default config support: PostgreSQL 10-19+
  • Legacy config support: PostgreSQL 9.1-9.6 via the legacy/ config bundle
  • pgBouncer support: 1.8-1.25+

See Release Notes for the full history.


Design Rationale

pg_exporter is built around a few simple production-oriented principles:

  • Local-first connectivity: fall back to postgresql:///?sslmode=disable when no explicit URL is provided, which fits same-host deployments
  • Declarative collection: metric behavior is driven by YAML collector definitions with precise control over ttl, timeout, tags, and fatal
  • Dynamic planning: choose the appropriate collector branch at runtime based on server version, role, extensions, and tags
  • Keep serving under failure: use non-blocking startup by default so HTTP endpoints still come up while the database is temporarily unavailable
  • Hot reload: support POST / GET /reload and SIGHUP reloads, with extra SIGUSR1 support on non-Windows platforms
  • Split probes from traffic: health endpoints use cached background probes instead of blocking the database on every request
  • Tighten the management surface: /reload, /explain, and /stat expose runtime and config details, so production deployments should protect them with --web.config.file or keep them internal

Installation

PG Exporter provides multiple installation methods to fit your infrastructure:

docker run -d --name pg_exporter -p 9630:9630 -e PG_EXPORTER_URL="postgres://user:pass@host:5432/postgres" pgsty/pg_exporter:latest
# RPM-based systems
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
enabled = 1
gpgcheck = 0
module_hotfixes=1
EOF

sudo yum makecache;
sudo yum install -y pg_exporter
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [trusted=yes] https://repo.pigsty.io/apt/infra generic main
EOF

sudo apt update;
sudo apt install -y pg-exporter
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"
mkdir -p "pg_exporter-${VERSION}.linux-amd64"
tar -xf "pg_exporter-${VERSION}.linux-amd64.tar.gz" -C "pg_exporter-${VERSION}.linux-amd64"
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
# Build from source
git clone https://github.com/pgsty/pg_exporter.git
cd pg_exporter
make build

Quick Start

Get PG Exporter up and running in minutes with Getting Started:

# Minimal startup with the local-first default URL
pg_exporter

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

# Access metrics
curl http://localhost:9630/metrics

# Reload configuration online (POST recommended)
curl -X POST http://localhost:9630/reload

Documentation


Live Demo

Experience PG Exporter in action with our live demo environment: https://g.pgsty.com

The demo showcases real PostgreSQL clusters monitored by PG Exporter, featuring:

  • Real-time metrics visualization with Grafana
  • Multiple PostgreSQL versions and configurations
  • Extension-specific metrics and monitoring
  • Complete observability stack powered by Pigsty

Community & Support

  • GitHub - Source code, issues, and contributions
  • Discussions - Ask questions and share experiences
  • Pigsty - Complete PostgreSQL Distro with PG Exporter

License

PG Exporter is open-source software licensed under the Apache License 2.0.

Copyright 2018-2026 © Ruohang Feng / [email protected]

1 - Getting Started

Get pg_exporter running and see PostgreSQL metrics in Prometheus within ten minutes

This page is the shortest path: install pg_exporter, connect it to a PostgreSQL instance, verify metrics output, and hook it into Prometheus.

You only need two things: a reachable PostgreSQL 10-19+ (or pgBouncer 1.8+) instance, and permission to create a user in it. For older PostgreSQL 9.1-9.6 instances, see Compatibility.


Step 1: Install

On Linux amd64 you can download the binary directly (for other platforms and RPM/DEB/Docker options, see the Installation guide):

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"
mkdir -p "pg_exporter-${VERSION}.linux-amd64"
tar -xf "pg_exporter-${VERSION}.linux-amd64.tar.gz" -C "pg_exporter-${VERSION}.linux-amd64"
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

Confirm the installation:

pg_exporter --version
# pg_exporter v1.4.1 (built with go1.26.5 on linux/amd64)

Step 2: Create a Monitoring User

Create a dedicated monitoring user on the target PostgreSQL. The built-in pg_monitor role (PostgreSQL 10+) covers all read permissions the default collectors need:

CREATE USER monitor WITH PASSWORD 'S3cret';
GRANT pg_monitor TO monitor;

If you are just trying it out locally as a superuser like postgres, you can skip this step.


Step 3: Run and Verify

Use --dry-run to confirm the configuration parses, then start for real:

export PG_EXPORTER_URL='postgres://monitor:S3cret@localhost:5432/postgres'

pg_exporter --dry-run     # print parsed collector config, then exit
pg_exporter               # start for real, listening on :9630 by default

Without any URL, pg_exporter falls back to the local-first default postgresql:///?sslmode=disable, which fits running on the same host as PostgreSQL. The full URL source precedence (--url > PG_EXPORTER_URL > PGURL > PG_EXPORTER_URL_FILE > default) is documented in the Deployment guide.

Pull the metrics from another terminal:

curl -s http://localhost:9630/metrics | grep -E '^pg_(up|version|in_recovery) '

You should see the three core built-in metrics:

pg_up 1              # 1 when the target is reachable, 0 otherwise
pg_version 170000    # version in server_version_num format
pg_in_recovery 0     # 1 on replicas, 0 on primaries

pg_up 1 means the pipeline works — the remaining 600+ metrics (pg_db_*, pg_table_*, pg_wal_*, …) all come from the declarative collector definitions in pg_exporter.yml. If pg_up is 0, restart with pg_exporter --log.level=debug and inspect the connection error.


Step 4: Hook into Prometheus

Add a scrape target in prometheus.yml:

scrape_configs:
  - job_name: 'postgresql'
    scrape_interval: 15s
    static_configs:
      - targets: ['localhost:9630']

Collectors cache results per their ttl (most realtime collectors use ttl: 10): as long as the TTL is below the scrape interval, every scrape gets fresh data, while high-frequency scraping can never overwhelm the database. This is also why setting scrape_interval below the common TTLs is not recommended.

That’s it. For Grafana, you can reuse the PostgreSQL dashboards from Pigsty, or explore the live demo.


Troubleshooting

SymptomWhat to do
pg_up 0, connection failsRun pg_exporter --log.level=debug and read the error; check URL, pg_hba.conf, and network reachability
Some metrics are missingcurl localhost:9630/explain to see each collector’s planning verdict (version gates, tags, predicates)
A collector keeps failingcurl localhost:9630/stat for per-collector error counters and durations
Scrapes are slowFind the slow collector in /stat, raise its ttl, or set skip: true

/stat, /explain, and /reload are management endpoints — protect them with --web.config.file (TLS/auth) or keep them on a trusted network in production. See the API Reference.


Next Steps

  • Monitor pgBouncer, enable auto-discovery, deploy with systemd / Docker / Kubernetes: Deployment guide
  • Understand and customize collectors (GAUGE/COUNTER/HISTOGRAM, TTL, tags, version gates): Configuration reference
  • Health check and primary/replica traffic routing endpoints (/up, /primary, /replica): API Reference

2 - Installation

How to download and install the pg_exporter

pg_exporter can be installed via Pigsty, YUM/APT repositories, GitHub release packages (RPM/DEB/Tarball), Docker images, or built from source — pick whichever fits your infrastructure.

Pigsty

The easiest way to get started with pg_exporter is to use Pigsty, which is a complete PostgreSQL distribution with built-in Observability best practices based on pg_exporter, Prometheus, and Grafana. You don’t even need to know any details about pg_exporter; it just gives you all the metrics and dashboard panels.

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty;

Release

You can also download pg_exporter package (RPM/DEB/ Tarball) directly from the Latest GitHub Release Page:

v1.4.1 Release Files:

TypeFile
DEB (amd64)pg-exporter_1.4.1-1_amd64.deb
DEB (arm64)pg-exporter_1.4.1-1_arm64.deb
DEB (ppc64le)pg-exporter_1.4.1-1_ppc64le.deb
RPM (aarch64)pg-exporter-1.4.1-1.aarch64.rpm
RPM (x86_64)pg-exporter-1.4.1-1.x86_64.rpm
RPM (ppc64le)pg-exporter-1.4.1-1.ppc64le.rpm
Tarball (Linux amd64)pg_exporter-1.4.1.linux-amd64.tar.gz
Tarball (Linux arm64)pg_exporter-1.4.1.linux-arm64.tar.gz
Tarball (Linux ppc64le)pg_exporter-1.4.1.linux-ppc64le.tar.gz
Tarball (macOS amd64)pg_exporter-1.4.1.darwin-amd64.tar.gz
Tarball (macOS arm64)pg_exporter-1.4.1.darwin-arm64.tar.gz
Tarball (Windows amd64)pg_exporter-1.4.1.windows-amd64.tar.gz

You can install it directly with your OS package manager (rpm/dpkg), or just place the binary in your $PATH. Current tarballs also include pg_exporter.yml, package/pg_exporter.default, package/pg_exporter.service, and LICENSE for manual deployments.

Full SHA256 checksums are available in checksums.txt on the release page; version-specific checksums are also archived in the release notes.

Repository

The pg_exporter package is also available in the pigsty-infra repo. You can add the repo to your system and install it with your OS package manager:

YUM

For EL distributions such as RHEL, Rocky Linux, CentOS, AlmaLinux, and Oracle Linux:

sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
enabled = 1
gpgcheck = 0
module_hotfixes=1
EOF

sudo yum makecache;
sudo yum install -y pg_exporter

APT

For Debian, Ubuntu and compatible Linux Distributions:

sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [trusted=yes] https://repo.pigsty.io/apt/infra generic main
EOF

sudo apt update;
sudo apt install -y pg-exporter

Docker

We have prebuilt docker images for amd64 and arm64 architectures on docker hub: pgsty/pg_exporter.

# Basic usage
docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -e PG_EXPORTER_URL="postgres://user:password@host: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:ro \
  -e PG_EXPORTER_CONFIG="/etc/pg_exporter.yml" \
  -e PG_EXPORTER_URL="postgres://user:password@host:5432/postgres" \
  pgsty/pg_exporter:latest

# With auto-discovery enabled
docker run -d \
  --name pg_exporter \
  -p 9630:9630 \
  -e PG_EXPORTER_URL="postgres://user:password@host:5432/postgres" \
  -e PG_EXPORTER_AUTO_DISCOVERY="true" \
  -e PG_EXPORTER_EXCLUDE_DATABASE="template0,template1" \
  pgsty/pg_exporter:latest

Compatibility

The default configuration supports PostgreSQL 10-19+. For EOL PostgreSQL versions, use the bundled legacy/ config package for compatible monitoring.

PostgreSQL VersionSupport Status
10 ~ 19+✅ Full Support (default config)
9.1 ~ 9.6⚠️ Use legacy/pg_exporter.yml
9.0 and earlier❌ Unsupported

Legacy config example:

make conf9
PG_EXPORTER_CONFIG=legacy/pg_exporter.yml pg_exporter

pg_exporter works with pgBouncer 1.8+, since v1.8 is the first version with SHOW command support.

pgBouncer VersionSupport Status
1.8.x ~ 1.25+✅ Full Support
before 1.8.x⚠️ No Metrics

3 - Configuration

Every business metric in pg_exporter is driven by a YAML collector definition: one SQL query plus its execution conditions (version, role, tags, predicates) and runtime controls (caching, timeout). This page is the complete reference for collector definitions.

A configuration can be a single YAML file (like the default pg_exporter.yml) or a directory of YAML files — the official default bundle is merged from the 58 definition files under config/.

Configuration Loading

PG Exporter searches for configuration in the following order:

  1. Command-line argument: --config=/path/to/config
  2. Environment variable: PG_EXPORTER_CONFIG=/path/to/config
  3. Current directory: ./pg_exporter.yml
  4. System config file: /etc/pg_exporter.yml
  5. System config directory: /etc/pg_exporter/

Directory mode details:

  • Only .yml / .yaml files in that directory are loaded, non-recursively
  • Files are merged in lexicographic order; later files override earlier collector definitions with the same top-level name
  • If a config directory contains YAML files but every one of them fails to parse, the exporter returns an error instead of silently ignoring the directory

Collector Structure

Each collector is a top-level object in the YAML configuration with a unique name and various properties:

collector_branch_name:           # Unique identifier for this collector
  name: metric_namespace         # Metric prefix (defaults to branch name)
  desc: "Collector description"  # Human-readable description
  query: |                       # SQL query to execute
    SELECT column1, column2
    FROM table

  # Execution Control
  ttl: 10                        # Cache time-to-live in seconds
  timeout: 0.1                   # Query timeout in seconds
  fatal: false                   # If true, failure fails entire scrape
  skip: false                    # If true, collector is disabled

  # Version Compatibility
  min_version: 100000            # Minimum PostgreSQL version (inclusive)
  max_version: 999999            # Maximum PostgreSQL version (exclusive)

  # Execution Tags
  tags: [cluster, primary]       # Conditions for execution

  # Predicate Queries (optional)
  predicate_queries:
    - name: "check_function"
      predicate_query: |
        SELECT EXISTS (...)

  # Metric Definitions
  metrics:
    - column_name:
        usage: GAUGE             # GAUGE, COUNTER, HISTOGRAM, LABEL, or DISCARD
        rename: metric_name      # Optional: rename the metric
        description: "Help text" # Metric description
        default: 0               # Default value if NULL
        scale: 1000              # Scale factor for the value
        bucket: [1, 10, 100]     # Bucket upper bounds for HISTOGRAM columns (strictly increasing, +Inf appended)

Validation rules:

  • Each entry in metrics must define exactly one column mapping
  • Each collector must expose at least one GAUGE, COUNTER, or HISTOGRAM column
  • usage only accepts GAUGE, COUNTER, HISTOGRAM, LABEL, or DISCARD
  • HISTOGRAM columns must define bucket: a finite, strictly increasing list of bucket upper bounds; the +Inf bucket is appended automatically
  • Metric names and label names are validated against Prometheus naming rules during load; invalid configs fail fast
  • Constant labels are checked for conflicts during load; they cannot overlap with query labels or built-in dynamic labels such as datname and query; when any HISTOGRAM collector is configured, le is reserved and cannot be used as a constant label
  • The SQL result must include every column declared as LABEL; since v1.4.1, a missing label column fails that collector’s entire scrape instead of emitting an empty label or retaining stale results, while other non-fatal collectors continue normally
  • If you use one-line inline metrics definitions, keep description values double-quoted to avoid YAML ambiguity

Core Configuration Elements

Collector Branch Name

The top-level key uniquely identifies a collector across the entire configuration:

pg_stat_database:  # Must be unique
  name: pg_db      # Actual metric namespace

Query Definition

The SQL query that retrieves metrics:

query: |
  SELECT 
    datname,
    numbackends,
    xact_commit,
    xact_rollback,
    blks_read,
    blks_hit
  FROM pg_stat_database
  WHERE datname NOT IN ('template0', 'template1')

Metric Types

Each column in the query result must be mapped to a metric type:

UsageDescriptionExample
GAUGEInstantaneous value that can go up or downCurrent connections
COUNTERCumulative value that only increasesTotal transactions
HISTOGRAMSnapshot histogram deriving _bucket / _count / _sum seriesTransaction age distribution
LABELUse as a Prometheus labelDatabase name
DISCARDIgnore this columnInternal values

Histogram Columns (HISTOGRAM)

v1.4.0 introduces the HISTOGRAM column type: every row returned by the query counts as one observation, aggregated per label group into a classic Prometheus histogram snapshot, deriving three series families: <name>_bucket (with the le label and the +Inf bucket), <name>_count, and <name>_sum:

pg_xact_age:
  name: pg_xact_age
  desc: "Open transaction age distribution histogram"
  query: |
    SELECT datname,
           greatest(0, extract(epoch FROM now() - xact_start)) AS seconds
    FROM pg_stat_activity
    WHERE pid <> pg_backend_pid() AND backend_type = 'client backend'
      AND datname IS NOT NULL AND xact_start IS NOT NULL;
  ttl: 10
  tags: [cluster]
  metrics:
    - datname: {usage: LABEL, description: "Database name"}
    - seconds:
        usage: HISTOGRAM
        bucket: [1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000, 100000]
        description: "Open transaction age snapshot in seconds"

Usage notes:

  • This is a snapshot histogram: the whole distribution is rebuilt on every scrape, so bucket counts can go up or down — gauge-like semantics. histogram_quantile() works directly, but rate() / increase() over _count / _sum is meaningless
  • SQL NULL observations are ignored by default; with an explicit default, they count as the default value
  • scale is applied to the observation before bucket assignment; as with scalar columns, timestamp and boolean values are exempt from scale
  • The pg_xact_age collector in the default bundle serves as the reference implementation

Cache Control (TTL)

The ttl parameter controls result caching:

# Fast queries - minimal caching
pg_stat_activity:
  ttl: 1  # Cache for 1 second

# Expensive queries - longer caching
pg_table_bloat:
  ttl: 3600  # Cache for 1 hour

Best practices:

  • Set TTL less than your scrape interval
  • Use longer TTL for expensive queries
  • TTL of 0 disables caching

Timeout Control

Prevent queries from running too long:

timeout: 0.1   # 100ms default
timeout: 1.0   # 1 second for complex queries
timeout: -1    # Disable timeout (not recommended)

Version Compatibility

Control which PostgreSQL versions can run this collector:

min_version: 100000  # PostgreSQL 10.0+
max_version: 140000  # Below PostgreSQL 14.0

Version numbers follow PostgreSQL server_version_num rules:

  • 100000 = 10.0
  • 130200 = 13.2
  • 160100 = 16.1
  • 190000 = 19.0
  • 90600 = 9.6, relevant when using the legacy config bundle

Execution Model

Understanding the full path from a collector definition to emitted metrics helps answer “why is this metric missing”:

  1. Planning (on connection setup or hot reload): each collector branch is checked in turn — target type (PostgreSQL / pgBouncer), min_version / max_version gates, tags matching against server role and exporter tags, and the skip switch. Branches that fail any check are not installed on that target. curl localhost:9630/explain shows exactly the verdict of this step.
  2. Scraping (on every /metrics request): for each installed collector — if the cache is still within ttl, the cached result is returned; otherwise predicate_queries run first (any false verdict skips this round and bumps pg_exporter_query_scrape_predicate_skip_count), then the main query executes under timeout, and results are converted to metrics and cached.
  3. Failure semantics: a normal collector failure only affects itself (pg_exporter_query_scrape_error_count goes up, its metric group is absent this round); a failing collector marked fatal: true fails the whole server scrape.

Tag System

Tags control when and where collectors execute:

Built-in Tags

TagDescription
clusterExecute once per PostgreSQL cluster
primary / masterOnly on primary servers
standby / replicaOnly on replica servers
pgbouncerOnly for pgBouncer connections

Prefixed Tags

PrefixExampleDescription
dbname:dbname:postgresOnly on specific database
username:username:monitorOnly with specific user
extension:extension:pg_stat_statementsOnly if extension installed
schema:schema:publicOnly if schema exists
not:not:slowNOT when exporter has tag

Custom Tags

Pass custom tags to the exporter:

pg_exporter --tag="production,critical"

Then use in configuration:

expensive_metrics:
  tags: [critical]  # Only runs with 'critical' tag

Predicate Queries

Execute conditional checks before main query:

predicate_queries:
  - name: "Check pg_stat_statements"
    predicate_query: |
      SELECT EXISTS (
        SELECT 1 FROM pg_extension 
        WHERE extname = 'pg_stat_statements'
      )

The main query only executes if all predicates return true.

Metric Definition

Basic Definition

metrics:
  - numbackends:
      usage: GAUGE
      description: "Number of backends connected"

Advanced Options

metrics:
  - checkpoint_write_time:
      usage: COUNTER
      rename: write_time        # Rename metric
      scale: 0.001              # Convert ms to seconds
      default: 0                # Use 0 if NULL
      description: "Checkpoint write time in seconds"

Collector Organization

PG Exporter ships with pre-organized collectors:

RangeCategoryDescription
0xxDocumentationExamples and documentation
1xxBasicServer info, settings, metadata
2xxReplicationReplication, slots, receivers
3xxPersistenceI/O, checkpoints, WAL
4xxActivityConnections, locks, queries
5xxProgressVacuum, index creation progress
6xxDatabasePer-database statistics
7xxObjectsTables, indexes, functions
8xxOptionalExpensive/optional metrics
9xxpgBouncerConnection pooler metrics
10xx+ExtensionsExtension-specific metrics

Real-World Examples

Simple Gauge Collector

pg_connections:
  desc: "Current database connections"
  query: |
    SELECT 
      count(*) as total,
      count(*) FILTER (WHERE state = 'active') as active,
      count(*) FILTER (WHERE state = 'idle') as idle,
      count(*) FILTER (WHERE state = 'idle in transaction') as idle_in_transaction
    FROM pg_stat_activity
    WHERE pid != pg_backend_pid()
  ttl: 1
  metrics:
    - total: {usage: GAUGE, description: "Total connections"}
    - active: {usage: GAUGE, description: "Active connections"}
    - idle: {usage: GAUGE, description: "Idle connections"}
    - idle_in_transaction: {usage: GAUGE, description: "Idle in transaction"}

Counter with Labels

pg_table_stats:
  desc: "Table statistics"
  query: |
    SELECT 
      schemaname,
      tablename,
      n_tup_ins,
      n_tup_upd,
      n_tup_del,
      n_live_tup,
      n_dead_tup
    FROM pg_stat_user_tables
  ttl: 10
  metrics:
    - schemaname: {usage: LABEL}
    - tablename: {usage: LABEL}
    - n_tup_ins: {usage: COUNTER, description: "Tuples inserted"}
    - n_tup_upd: {usage: COUNTER, description: "Tuples updated"}
    - n_tup_del: {usage: COUNTER, description: "Tuples deleted"}
    - n_live_tup: {usage: GAUGE, description: "Live tuples"}
    - n_dead_tup: {usage: GAUGE, description: "Dead tuples"}

Version-Specific Collector

pg_wal_stats:
  desc: "WAL statistics (PG 14+)"
  min_version: 140000
  query: |
    SELECT 
      wal_records,
      wal_bytes,
      wal_buffers_full,
      wal_write_time,
      wal_sync_time
    FROM pg_stat_wal
  ttl: 10
  tags: [cluster]
  metrics:
    - wal_records: {usage: COUNTER}
    - wal_bytes: {usage: COUNTER}
    - wal_buffers_full: {usage: COUNTER}
    - wal_write_time: {usage: COUNTER, scale: 0.001}
    - wal_sync_time: {usage: COUNTER, scale: 0.001}

Extension-Dependent Collector

pg_stat_statements_metrics:
  desc: "Query performance statistics"
  tags: [extension:pg_stat_statements]
  query: |
    SELECT 
      sum(calls) as total_calls,
      sum(total_exec_time) as total_time,
      sum(mean_exec_time * calls) / sum(calls) as mean_time
    FROM pg_stat_statements
  ttl: 60
  metrics:
    - total_calls: {usage: COUNTER}
    - total_time: {usage: COUNTER, scale: 0.001}
    - mean_time: {usage: GAUGE, scale: 0.001}

Custom Collectors

Creating Your Own Metrics

  1. Create a new YAML file in your config directory:
# /etc/pg_exporter/custom_metrics.yml
app_metrics:
  desc: "Application-specific metrics"
  query: |
    SELECT 
      (SELECT count(*) FROM users WHERE active = true) as active_users,
      (SELECT count(*) FROM orders WHERE created_at > NOW() - '1 hour'::interval) as recent_orders,
      (SELECT avg(processing_time) FROM jobs WHERE completed_at > NOW() - '5 minutes'::interval) as avg_job_time
  ttl: 30
  metrics:
    - active_users: {usage: GAUGE, description: "Currently active users"}
    - recent_orders: {usage: GAUGE, description: "Orders in last hour"}
    - avg_job_time: {usage: GAUGE, description: "Average job processing time"}
  1. Test your collector:
pg_exporter --explain --config=/etc/pg_exporter/

Conditional Metrics

Use predicate queries for conditional metrics:

partition_metrics:
  desc: "Partitioned table metrics"
  predicate_queries:
    - name: "Check if partitioning is used"
      predicate_query: |
        SELECT EXISTS (
          SELECT 1 FROM pg_class 
          WHERE relkind = 'p' LIMIT 1
        )
  query: |
    SELECT 
      parent.relname as parent_table,
      count(*) as partition_count,
      sum(pg_relation_size(child.oid)) as total_size
    FROM pg_inherits
    JOIN pg_class parent ON parent.oid = pg_inherits.inhparent
    JOIN pg_class child ON child.oid = pg_inherits.inhrelid
    WHERE parent.relkind = 'p'
    GROUP BY parent.relname
  ttl: 300
  metrics:
    - parent_table: {usage: LABEL}
    - partition_count: {usage: GAUGE}
    - total_size: {usage: GAUGE}

Performance Optimization

Query Optimization Tips

  1. Use appropriate TTL values:

    • Fast queries: 1-10 seconds
    • Medium queries: 10-60 seconds
    • Expensive queries: 300-3600 seconds
  2. Set realistic timeouts:

    • Default: 100ms
    • Complex queries: 500ms-1s
    • Never disable timeout in production
  3. Use cluster-level tags:

    tags: [cluster]  # Run once per cluster, not per database
    
  4. Disable expensive collectors:

    pg_table_bloat:
      skip: true  # Disable if not needed
    

Monitoring Collector Performance

Check collector execution statistics:

# View collector statistics (hit / error / skip counters and durations)
curl http://localhost:9630/stat

# Per-collector duration and error counters, by datname/query
curl -s http://localhost:9630/metrics | grep -E 'pg_exporter_query_scrape_(duration|error_count)'

Troubleshooting Configuration

Validate Configuration

# Dry run - shows parsed configuration
pg_exporter --dry-run

# Explain - shows planned queries
pg_exporter --explain

Common Issues

ProblemSolution
Metrics missingCheck tags and version compatibility
Slow scrapesIncrease TTL, add timeout, disable expensive queries
High memory usageReduce result set size, use LIMIT
Permission errorsVerify query permissions for monitoring user

Debug Logging

Enable debug logging to troubleshoot:

pg_exporter --log.level=debug

4 - API Reference

pg_exporter exposes four kinds of HTTP endpoints on its listen port (default :9630): metrics, health checks, traffic routing, and operational management. The full endpoint list:

EndpointMethodDescription
/metricsGETPrometheus metrics endpoint (path configurable via --web.telemetry-path)
/upGETAliveness check; aliases /health, /liveness, /readiness, /read
/primaryGETPrimary check; aliases /leader, /master, /read-write, /rw
/replicaGETReplica check; aliases /standby, /slave, /read-only, /ro
/reloadGET/POSTHot-reload collector configuration
/explainGETShow per-collector planning decisions
/statGETPer-collector runtime statistics (hits / errors / duration)
/versionGETVersion and build information (plain text)
/GETLanding page linking to the metrics endpoint

Health and routing endpoints answer from a cached background-probe role state (primary / replica / down / starting / unknown) — they never query the database synchronously per HTTP request, so probe storms cannot reach the database.


Metrics Endpoint

GET /metrics

The primary endpoint that exposes all collected metrics in Prometheus format.

Request

curl http://localhost:9630/metrics

Response

# HELP pg_up last scrape was able to connect to the server: 1 for yes, 0 for no
# TYPE pg_up gauge
pg_up 1

# HELP pg_version server version number
# TYPE pg_version gauge
pg_version 140000

# HELP pg_in_recovery server is in recovery mode? 1 for yes 0 for no
# TYPE pg_in_recovery gauge
pg_in_recovery 0

# HELP pg_exporter_build_info A metric with a constant '1' value labeled with version, revision, branch, goversion, builddate, goos, and goarch from which pg_exporter was built.
# TYPE pg_exporter_build_info gauge
pg_exporter_build_info{version="v1.4.1",branch="main",revision="<git-sha>",builddate="<build-date>",goversion="go1.26.5",goos="linux",goarch="amd64"} 1

# ... additional metrics

Response Format

Metrics follow the Prometheus exposition format:

# HELP <metric_name> <description>
# TYPE <metric_name> <type>
<metric_name>{<label_name>="<label_value>",...} <value> <timestamp>

Self-Monitoring Metrics

Besides business metrics defined by YAML collectors, /metrics also exposes the exporter’s own runtime metrics (disable the pg_exporter_* part with --disable-intro; the prefix follows --namespace and becomes pgbouncer_ in pgBouncer mode):

MetricLabelsDescription
pg_up1 when the target database is reachable, 0 otherwise
pg_versionServer version in server_version_num format
pg_in_recovery1 when in recovery mode (replica)
pg_exporter_build_infoversion, revision, …Constant 1 with build info in labels
pg_exporter_upConstant 1 while the exporter is alive
pg_exporter_uptimeSeconds since the exporter started
pg_exporter_scrape_total_count / _error_countCumulative scrape / failure counts
pg_exporter_scrape_durationDuration of the last scrape in seconds
pg_exporter_last_scrape_timeTimestamp of the last scrape
pg_exporter_server_scrape_*datnamePer-database scrape duration and success/failure counters
pg_exporter_query_scrape_durationdatname, queryLast execution duration per collector
pg_exporter_query_scrape_total_count / _error_countdatname, queryExecution / failure counts per collector
pg_exporter_query_scrape_hit_count / _metric_countdatname, queryRows returned / metrics emitted per collector
pg_exporter_query_scrape_predicate_skip_countdatname, queryTimes skipped because a predicate returned false
pg_exporter_query_cache_ttldatname, queryResult cache TTL per collector

pg_exporter_query_scrape_duration and _error_count pinpoint slow and failing collectors directly — the machine-readable equivalent of /stat.


Health Checks

Health endpoints provide multiple ways to monitor PG Exporter and the target database state.

GET /up

Simple aliveness check based on cached background probe state. It does not actively probe the database on every HTTP request.

Response Codes

CodeStatusDescription
200OKTarget is available (primary / replica)
503Service UnavailableTarget is unavailable (down / starting / unknown)

Example

# Check whether the service is healthy
curl -I http://localhost:9630/up

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

GET /health

Alias of /up with identical behavior.

curl http://localhost:9630/health

GET /liveness and GET /readiness

Path aliases provided for Kubernetes probe conventions, with behavior identical to /up (same handler):

livenessProbe:
  httpGet: { path: /liveness, port: 9630 }
  initialDelaySeconds: 30
  periodSeconds: 10
readinessProbe:
  httpGet: { path: /readiness, port: 9630 }
  initialDelaySeconds: 5
  periodSeconds: 5

Note that both share the same semantics: they return 503 when the target database is unreachable. If you don’t want “database down” to restart the exporter Pod, use a TCP probe on the listen port for liveness instead.


Traffic Routing

These endpoints are designed for load balancers and proxies to route traffic based on server role.

GET /primary

Check whether the server is a primary instance.

Response Codes

CodeStatusDescription
200OKServer is primary and accepting writes
404Not FoundServer is not primary and is acting as a replica
503Service UnavailableServer is unavailable (down / starting / unknown)

Aliases

  • /leader
  • /master
  • /read-write
  • /rw

Example

# Check whether the server is primary
curl -I http://localhost:9630/primary

# Use in HAProxy
backend pg_primary
  option httpchk GET /primary
  server pg1 10.0.0.1:5432 check port 9630
  server pg2 10.0.0.2:5432 check port 9630

GET /replica

Check whether the server is a replica instance.

Response Codes

CodeStatusDescription
200OKServer is a replica and in recovery
404Not FoundServer is not a replica and is acting as primary
503Service UnavailableServer is unavailable (down / starting / unknown)

Aliases

  • /standby
  • /read-only
  • /ro

/slave remains compatible, but /replica is the preferred name.

Example

# Check whether the server is a replica
curl -I http://localhost:9630/replica

# Use in a load balancer
backend pg_replicas
  option httpchk GET /replica
  server pg2 10.0.0.2:5432 check port 9630
  server pg3 10.0.0.3:5432 check port 9630

GET /read

Check whether the server can handle read traffic. Both primaries and replicas may return success.

Response Codes

CodeStatusDescription
200OKServer is healthy and can handle reads
503Service UnavailableServer is unavailable (down / starting / unknown)

Example

# Check whether the server can serve reads
curl -I http://localhost:9630/read

# Route reads to any healthy server
backend pg_read
  option httpchk GET /read
  server pg1 10.0.0.1:5432 check port 9630
  server pg2 10.0.0.2:5432 check port 9630
  server pg3 10.0.0.3:5432 check port 9630

Operational Endpoints

GET /reload / POST /reload

Reload configuration without restarting the exporter.

Request

# POST is recommended
curl -X POST http://localhost:9630/reload

# GET remains supported for compatibility
curl http://localhost:9630/reload

Response

server reloaded

Response Codes

CodeStatusDescription
200OKReload completed successfully
500Internal Server ErrorReload failed and returns fail to reload: ...
405Method Not AllowedNon-GET/POST request, with Allow: GET, POST

Use Cases

  • Update collector definitions
  • Change query parameters
  • Modify cache TTL values
  • Add or remove collectors

GET /explain

Display planned collector execution details for all configured collectors.

Request

curl http://localhost:9630/explain

Response

##
# SYNOPSIS
#       pg.pg_primary_only_*
#
# DESCRIPTION
#       PostgreSQL basic information (on primary)
#
# OPTIONS
#       Tags       [cluster, primary]
#       TTL        1
#       Priority   110
#       Timeout    100ms
#       Fatal      true
#       Version    100000 ~ higher
#       Source     pg_exporter.yml

...

GET /stat

Show runtime statistics, including collector execution times and success/error counters.

Request

curl http://localhost:9630/stat

Response

name                     total      hit        error      skip       metric     ttl/s  duration/ms
pg                       12         0          0          0          15         1      4.231000
pg_db                    12         11         0          0          28         10     0.153000
pg_activity              12         0          1          0          8          0      7.842000
...

This endpoint is useful when identifying slow or problematic collectors.


Using with Load Balancers

HAProxy Example

# Primary backend for write traffic
backend pg_primary
  mode tcp
  option httpchk GET /primary
  http-check expect status 200
  server pg1 10.0.0.1:5432 check port 9630 inter 3000 fall 2 rise 2
  server pg2 10.0.0.2:5432 check port 9630 inter 3000 fall 2 rise 2 backup

# Replica backend for read traffic
backend pg_replicas
  mode tcp
  balance roundrobin
  option httpchk GET /replica
  http-check expect status 200
  server pg2 10.0.0.2:5432 check port 9630 inter 3000 fall 2 rise 2
  server pg3 10.0.0.3:5432 check port 9630 inter 3000 fall 2 rise 2

# Read backend for any server that can handle reads
backend pg_read
  mode tcp
  balance leastconn
  option httpchk GET /read
  http-check expect status 200
  server pg1 10.0.0.1:5432 check port 9630 inter 3000 fall 2 rise 2
  server pg2 10.0.0.2:5432 check port 9630 inter 3000 fall 2 rise 2
  server pg3 10.0.0.3:5432 check port 9630 inter 3000 fall 2 rise 2

A Note on Nginx

Open-source Nginx does not support active out-of-band HTTP health checks (the health_check directive is an NGINX Plus feature), and PostgreSQL traffic requires the stream module rather than http proxying. For role-based PostgreSQL traffic routing, prefer HAProxy as shown above, or solutions like Patroni + vip-manager.

5 - Deployment

Production deployment — connection & credentials, systemd / Docker / Kubernetes, auto-discovery and alerting

This page covers what it takes to run pg_exporter in production: process arguments and environment variables, monitoring user and credential management, the systemd / Docker / Kubernetes deployment forms, pgBouncer and auto-discovery, plus scrape and alerting configuration on the Prometheus side.

Process-level configuration comes from two sources, in decreasing precedence:

  1. Command-line arguments (--url, --config, …)
  2. Environment variables (every flag has a corresponding PG_EXPORTER_* variable)

Metric collection behavior is entirely driven by YAML collector definitions (default /etc/pg_exporter.yml, or a config directory) — see the Configuration reference.


Command-Line Arguments

pg_exporter \
  --url="postgres://monitor:S3cret@localhost:5432/postgres" \
  --config="/etc/pg_exporter.yml" \
  --web.listen-address=":9630" \
  --auto-discovery \
  --log.level="info"

The full flag list from pg_exporter --help:

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.

Two deployment-relevant behaviors worth knowing:

  • Startup policy: non-blocking startup is the default — when the target database is temporarily unreachable, the HTTP endpoints come up anyway and a background probe keeps retrying until recovery. If you prefer “fail on unreachable” (e.g. delegating restart decisions to systemd or an orchestrator), set --fail-fast.
  • Telemetry path validation: since v1.4.0, --web.telemetry-path is strictly validated at startup — empty paths, conflicts with built-in endpoints, or non-canonical paths like //metrics that could never match fail immediately with a clear error.

Connection URL Sources

The connection string resolves from the following sources, first non-empty value wins:

  1. --url / -u command-line argument
  2. PG_EXPORTER_URL environment variable
  3. PGURL environment variable
  4. Content of the file pointed to by PG_EXPORTER_URL_FILE (fits container Secret mounts)
  5. Default postgresql:///?sslmode=disable (local-first, fits same-host deployment)

When the URL omits sslmode, sslmode=disable is appended automatically. Also, libpq service-file environment variables (PGSERVICE / PGSERVICEFILE, etc.) are cleared at startup with a log line — service files could override the explicit connection target, and pg_exporter guarantees that the URL announced in logs is the URL actually connected to.


Monitoring User and Credentials

Create the Monitoring User

CREATE ROLE monitor WITH LOGIN PASSWORD 'S3cret' CONNECTION LIMIT 5;
GRANT pg_monitor TO monitor;   -- built-in monitoring role (PostgreSQL 10+), covers all default collectors

Keeping CONNECTION LIMIT is recommended: the exporter normally holds only one to a few connections (one per database with auto-discovery), and the limit prevents connection exhaustion on misconfiguration.

Manage Passwords with .pgpass

Take the password out of the URL and let libpq’s .pgpass provide it:

# Create as the OS user that runs the exporter
echo "localhost:5432:*:monitor:S3cret" > ~/.pgpass
chmod 600 ~/.pgpass

# URL without password
PG_EXPORTER_URL='postgres://monitor@localhost:5432/postgres'

TLS for the Database Connection

PG_EXPORTER_URL='postgres://monitor:[email protected]:5432/postgres?sslmode=verify-full&sslrootcert=/etc/pki/ca.crt'

Protecting the HTTP Port

Beyond /metrics, the /reload, /explain, and /stat management endpoints let anyone with port access read configuration and runtime state, or trigger reloads. If the exporter is reachable from a shared network, enable TLS / Basic Auth via --web.config.file (exporter-toolkit web configuration), or restrict access at the firewall / reverse-proxy layer.


Systemd Deployment (RPM/DEB packages)

The RPM/DEB packages ship a service unit and an environment file; after installation, edit the environment file and start:

# /usr/lib/systemd/system/pg_exporter.service
[Unit]
Description=Prometheus exporter for PostgreSQL/Pgbouncer server metrics
Documentation=https://pigsty.io/docs/pg_exporter
After=network.target

[Service]
EnvironmentFile=-/etc/default/pg_exporter
User=prometheus
ExecStart=/usr/bin/pg_exporter $PG_EXPORTER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target

Environment file /etc/default/pg_exporter (package defaults):

PG_EXPORTER_URL='postgres://:5432/postgres?sslmode=disable'
PG_EXPORTER_CONFIG=/etc/pg_exporter.yml
PG_EXPORTER_LABEL=""
PG_EXPORTER_TAG=""
PG_EXPORTER_DISABLE_CACHE=false
PG_EXPORTER_AUTO_DISCOVERY=true
PG_EXPORTER_EXCLUDE_DATABASE="template0,template1,postgres"
PG_EXPORTER_INCLUDE_DATABASE=""
PG_EXPORTER_NAMESPACE="pg"
PG_EXPORTER_FAIL_FAST=false
PG_EXPORTER_CONNECT_TIMEOUT=100
PG_EXPORTER_TELEMETRY_PATH="/metrics"
PG_EXPORTER_OPTS='--log.level=info'

Every command-line flag has a corresponding environment variable — append what you need here (e.g. PG_EXPORTER_DISABLE_INTRO). The file is packaged as noreplace, so upgrades never overwrite your edits.

Common operations:

sudo systemctl enable --now pg_exporter    # start and enable at boot
sudo systemctl status pg_exporter          # check status
journalctl -u pg_exporter -f               # follow logs
curl -X POST localhost:9630/reload         # hot-reload collector config (no restart)

Docker Deployment

docker run -d \
  --name pg_exporter \
  --restart unless-stopped \
  -p 9630:9630 \
  -e PG_EXPORTER_URL="postgres://monitor:S3cret@host:5432/postgres" \
  pgsty/pg_exporter:latest

Docker Compose:

services:
  pg_exporter:
    image: pgsty/pg_exporter:latest
    container_name: pg_exporter
    restart: unless-stopped
    ports:
      - "9630:9630"
    environment:
      - PG_EXPORTER_URL=postgres://monitor:S3cret@postgres:5432/postgres
    volumes:
      - ./pg_exporter.yml:/etc/pg_exporter.yml:ro   # optional: custom collector config
    depends_on:
      - postgres

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pg-exporter
  labels: { app: pg-exporter }
spec:
  replicas: 1
  selector:
    matchLabels: { app: pg-exporter }
  template:
    metadata:
      labels: { app: pg-exporter }
    spec:
      containers:
      - name: pg-exporter
        image: pgsty/pg_exporter:latest
        ports:
        - containerPort: 9630
        env:
        - name: PG_EXPORTER_URL
          valueFrom:
            secretKeyRef:
              name: pg-credentials
              key: connection-url
        livenessProbe:
          httpGet: { path: /liveness, port: 9630 }
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet: { path: /readiness, port: 9630 }
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests: { cpu: 100m, memory: 128Mi }
          limits: { cpu: 200m, memory: 256Mi }
---
apiVersion: v1
kind: Service
metadata:
  name: pg-exporter
  labels: { app: pg-exporter }
spec:
  ports:
  - { port: 9630, targetPort: 9630, name: metrics }
  selector: { app: pg-exporter }

You can also use PG_EXPORTER_URL_FILE pointing at a Secret-mounted file, keeping the connection string out of environment variables.


Auto-Discovery

Auto-discovery (enabled by default) lets one exporter instance monitor every database in the target PostgreSQL:

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 to switch to pgBouncer mode (this is what triggers the detection):

PG_EXPORTER_URL='postgres://stats_user:S3cret@localhost:6432/pgbouncer' pg_exporter

In pgBouncer mode, the exporter uses the pgbouncer metric prefix and runs only pgBouncer-specific collectors (SHOW STATS / SHOW POOLS, etc.). The usual pattern is one exporter instance for PostgreSQL and another for pgBouncer, on different ports.


Prometheus Scraping and Alerting

Scrape Configuration

scrape_configs:
  - job_name: 'postgresql'
    scrape_interval: 15s
    static_configs:
      - targets: ['pg-1:9630', 'pg-2:9630', 'pg-3:9630']

Kubernetes service discovery:

scrape_configs:
  - job_name: 'postgresql'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_label_app]
        regex: pg-exporter
        action: keep
      - source_labels: [__meta_kubernetes_pod_ip]
        target_label: __address__
        replacement: ${1}:9630

Keep the scrape interval at or above the common collector ttl (mostly 10 seconds in the default bundle): TTL caching means more frequent scrapes would only receive cached results anyway.

Alert Rules

All rules below are based on metrics that actually exist:

groups:
  - name: pg_exporter
    rules:
      # Exporter process unreachable
      - alert: PgExporterDown
        expr: up{job="postgresql"} == 0
        for: 1m
        labels: { severity: critical }
        annotations:
          summary: "pg_exporter down ({{ $labels.instance }})"

      # Exporter alive but cannot reach the database
      - alert: PostgreSQLDown
        expr: pg_up == 0
        for: 1m
        labels: { severity: critical }
        annotations:
          summary: "PostgreSQL connection failed ({{ $labels.instance }})"

      # Overall scrape duration abnormal (unit: seconds)
      - alert: PgExporterSlowScrape
        expr: pg_exporter_scrape_duration > 10
        for: 5m
        labels: { severity: warning }
        annotations:
          summary: "pg_exporter slow scrape ({{ $labels.instance }})"

      # A specific collector keeps failing (locate by datname/query)
      - alert: PgExporterQueryError
        expr: increase(pg_exporter_query_scrape_error_count[10m]) > 0
        for: 10m
        labels: { severity: warning }
        annotations:
          summary: "Collector {{ $labels.query }} keeps failing on {{ $labels.datname }}"

Role-Based Traffic Routing

The /primary, /replica, and /read health-check endpoints can serve directly as health probes for HAProxy and similar load balancers, enabling primary/replica read-write splitting. Endpoint semantics and a complete HAProxy example are in the API Reference.

Note: open-source Nginx does not support active out-of-band HTTP health checks (health_check is an NGINX Plus feature). For role-based PostgreSQL traffic routing, prefer HAProxy, or solutions like Patroni + vip-manager.

6 - Release Notes

The latest stable version of pg_exporter is v1.4.1

VersionDateSummaryGitHub
v1.4.12026-07-29Subscription count and label validation fixes; RPM renamev1.4.1
v1.4.02026-07-18Snapshot histograms, pg_xact_age collector, HTTP hardeningv1.4.0
v1.3.02026-06-24PostgreSQL 19 support, new PG19 collectors and branchesv1.3.0
v1.2.22026-04-14Routine Go 1.26.2 refresh, no functional changesv1.2.2
v1.2.12026-03-21Config style cleanup, Go 1.26.1 refreshv1.2.1
v1.2.02026-02-12Hot reload, non-blocking startup, PG9.x legacy supportv1.2.0
v1.1.22026-01-16fix pg_timeline conf issue, build with latest depsv1.1.2
v1.1.12025-12-30New pg_timeline collector, pg_sub_16 branch, bug fixesv1.1.1
v1.1.02025-12-15Update default metrics collectors, bump to go 1.25.5v1.1.0
v1.0.32025-11-20Routine update on 1.25.4, fix unsupported libpq envv1.0.3
v1.0.22025-08-14Build for more os arch with goreleaserv1.0.2
v1.0.12025-07-17DockerHub images, Go 1.24.5, disable pg_tsdb_hypertablev1.0.1
v1.0.02025-05-06PostgreSQL 18 support, new WAL/checkpointer/I/O metricsv1.0.0
v0.9.02025-04-26TimescaleDB, Citus, pg_wait_sampling collectorsv0.9.0
v0.8.12025-02-14Dependencies update, docker image tagsv0.8.1
v0.8.02025-02-14PgBouncer 1.24 support, Go 1.24, logging refactorv0.8.0
v0.7.12024-12-29Routine update, configuration as Reader supportv0.7.1
v0.7.02024-08-13PostgreSQL 17 support, predicate queries featurev0.7.0
v0.6.02023-10-18PostgreSQL 16 support, ARM64 packages, security fixesv0.6.0
v0.5.02022-04-27RPM/DEB builds, column scaling, metrics enhancementsv0.5.0
v0.4.12022-03-08Collector updates, connect-timeout parameterv0.4.1
v0.4.02021-07-12PostgreSQL 14 support, auto-discovery featurev0.4.0
v0.3.22021-02-01Shadow DSN fixes, documentation updatesv0.3.2
v0.3.12020-12-04Configuration fixes for older PostgreSQL versionsv0.3.1
v0.3.02020-10-29PostgreSQL 13 support, REST APIs, dummy serverv0.3.0
v0.2.02020-03-21YUM packages, configuration reload supportv0.2.0
v0.1.22020-02-20Dynamic configuration reload, bulky modev0.1.2
v0.1.12020-01-10Startup hang bug fixv0.1.1
v0.1.02020-01-08Initial stable releasev0.1.0
v0.0.42019-12-20Production tested releasev0.0.4
v0.0.32019-12-14Production environment testingv0.0.3
v0.0.22019-12-09Early testing releasev0.0.2
v0.0.12019-12-06Initial release with PgBouncer modev0.0.1

v1.4.1

v1.4.1 is a maintenance release focused on metric accuracy and RPM upgrade compatibility.

Highlights:

  • Fix pg_subrel_count overcounting when parallel logical replication apply workers are active: deduplicate pg_stat_subscription by subscription ID and name before aggregating subscription relation states
  • If a query result omits a configured LABEL column, that collector’s scrape now fails atomically instead of emitting an empty label or retaining stale results; other non-fatal collectors continue normally
  • Rename the official RPM package and artifact prefix from pg_exporter to pg-exporter; the new package provides and obsoletes the legacy name, allowing direct upgrades
  • Refresh version and standalone package metadata, add missing-label regression coverage, and validate RPM configuration, artifact names, and compatibility metadata in CI

Upgrade Notes:

  • Custom collector SQL must return every LABEL column; the result schema must remain complete even when the query returns zero rows
  • If automation matches GitHub RPM file names directly, update pg_exporter-*.rpm to pg-exporter-*.rpm

https://github.com/pgsty/pg_exporter/releases/tag/v1.4.1

v1.4.0

v1.4.0 introduces the Snapshot Histogram metric type and the new pg_xact_age transaction age collector, along with a round of systematic hardening across HTTP routing, packaging, and the build toolchain.

New Features:

  • New HISTOGRAM column type: SQL query snapshots can be aggregated per label group into classic Prometheus histograms, deriving _bucket / _count / _sum series families; bucket bounds are strictly validated at config load time (finite, strictly increasing, +Inf appended automatically), le becomes a reserved label, and hot reload is fully supported
  • New pg_xact_age collector: exposes the distribution of open transaction age (pg_xact_age_seconds) and idle-in-transaction age (pg_xact_age_idle_seconds) as histograms; cluster-level collection, client backends only, 10s TTL
  • Default config bundle grows from 57 to 58 definition files; pg_xact_age takes slot 0450, with pg_lock / pg_lock_stat / pg_query renumbered to 0460 / 0470 / 0480 (contents unchanged)

Fixes & Improvements:

  • HTTP route registration is isolated to a private ServeMux instead of the global DefaultServeMux, so endpoints registered by third-party libraries can no longer be exposed accidentally
  • --web.telemetry-path is strictly validated at startup: empty paths, paths not starting with /, paths containing ? # { }, conflicts with built-in endpoints, and non-canonical paths like //metrics that could never be matched all fail fast with a clear error
  • The landing page HTML-escapes the telemetry path
  • The primary connection pool is properly closed when --fail-fast pre-check fails
  • RPM / DEB packaging fixes (#105): the prometheus system user’s HOME now points to /var/lib/prometheus (where libpq looks for ~/.pgpass), and the packaged default URL gains the /postgres database name so libpq no longer falls back to a database named after the OS user
  • Version string unified with the v prefix: --version output, the /version endpoint, and the pg_exporter_build_info{version=...} label of official release binaries now report v1.4.0 (GoReleaser artifacts previously reported unprefixed 1.3.0); artifact file names, package versions, and Docker image tag conventions are unchanged
  • Histogram value casting aligned with the scalar path: timestamp and boolean columns are exempt from scale
  • GoReleaser embedded package metadata corrected: supported range updated to PostgreSQL 9.x - 19+ and pgBouncer 1.8 - 1.25+
  • make docker restores GOPROXY / GOSUMDB build-arg passthrough

Engineering & Build:

  • Build toolchain updated to Go 1.26.5, exporter-toolkit v0.17.1, and prometheus/common v0.70.0
  • New regular CI verification workflow: module tidy check, generated-config drift check (make conf output must stay in sync with config/*.yml), race tests, and six-platform cross-builds
  • Docker build tooling consolidated: the docker/ scripts and make docker-release are removed; multi-arch release images are built by GoReleaser
  • Config coverage tests generalized: tests no longer assume specific collectors exist in the config directory, making trimmed custom bundles easier to maintain

Upgrade Notes:

  • If you were running with a non-canonical telemetry path (e.g. //metrics), the process will now refuse to start — previously it started but the metrics endpoint was silently unreachable
  • Automation that parses the version label of pg_exporter_build_info or the --version output needs to accommodate the v prefix
  • When any HISTOGRAM collector is configured, le can no longer be used as a constant label

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.4.0/checksums.txt

9874191591567ede87ae1d5820f06e781f27c664a7f4a6365211f9e042fd8199  checksums.txt
c6af4ae62e13f518539a6d0b3ce86ff9f7acdb567a4f0f86c6f47563574da724  pg-exporter_1.4.0-1_amd64.deb
ff0360f61982ed627d1b1f93281a0ba66da9d077672f0c214e19522df01e40d6  pg-exporter_1.4.0-1_arm64.deb
4fbadd4e9d918c9bc8e63975378e49375b0ff897d6b8a0f78799538b13dd68a1  pg-exporter_1.4.0-1_ppc64le.deb
5ce106d27fffa77c39fea9bf7cbc60f4328df3d926fef025bfdd082eb6d743fd  pg_exporter-1.4.0-1.aarch64.rpm
870b434e802e0039f10e1e3583c28a1fd83db4363a4608e1fab7f375f6d30600  pg_exporter-1.4.0-1.ppc64le.rpm
c550d16ce3f9276948a4d44174e11716fc5e85e31e8788ea106a57cfbabd8488  pg_exporter-1.4.0-1.x86_64.rpm
11a34e531ac5d6d378b91e768f575525389141a6860afabd0cc9f2d853f06749  pg_exporter-1.4.0.darwin-amd64.tar.gz
49d8d3a5932602f433c4ef681ed12007da1cbc11b5ee0f9d7b4dc2d0dff8e26e  pg_exporter-1.4.0.darwin-arm64.tar.gz
113dfe70d4f780a456c05ca6b731f96c1013bf35ecb87d75c443fe2bac7e333b  pg_exporter-1.4.0.linux-amd64.tar.gz
68b4630ab39943658a8aff135990896a5ccf56c8a992e5982d572c78ef822e18  pg_exporter-1.4.0.linux-arm64.tar.gz
72710625e5658c941b48f7becba9a86491852cea5469240328292838d9ed0979  pg_exporter-1.4.0.linux-ppc64le.tar.gz
14a0cf6ffa04c7e54c1d5aa5b37fe4bea1429c1d1e7cce89e9dd805c4a29db0b  pg_exporter-1.4.0.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.4.0


v1.3.0

v1.3.0 adds PostgreSQL 19 support, and refreshes the default collector bundle, build toolchain, and config coverage tests.

Highlights:

  • Default support range extended from PostgreSQL 10-18+ to 10-19+
  • Default config bundle includes 57 config/*.yml definition files
  • Build dependencies updated to Go 1.26.4, lib/pq v1.12.3, Prometheus client v1.23.2, and exporter-toolkit v0.16.0
  • pg_recovery_state: collect pg_stat_recovery on recovery nodes, exposing promotion trigger status, replay LSN, timeline, recovery transaction time, and pause state
  • pg_lock_stat: collect PG19 pg_stat_lock, exposing waits, wait time, and fast-path overflow counts by locktype
  • pg_vacuum_score: collect the current-database summary from pg_stat_autovacuum_scores, exposing max autovacuum score and candidate table count
  • pg_wal_19: expose wal_fpi_bytes on PG19 as pg_wal_fpi_bytes
  • pg_sub_19: adapt sequence sync and logical replication conflict stats from pg_stat_subscription_stats, while keeping sync_error_count for legacy dashboards
  • pg_recv: recognize the PG13+ WAL receiver connecting state on PG19
  • pg_slot: recognize the PG19 replication slot invalidation reason idle_timeout
  • pg_db_confl: switch to an explicit column list to avoid accidentally exporting future view columns
  • pg_backup, pg_vacuuming, and pg_clustering continue reusing stable existing branches instead of changing the metric surface for low-value PG19 fields

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.3.0/checksums.txt

c88c4ad7cde10531d75ec98fa536b2e7f531639f55c3b3c9866ee76934a4e2b2  checksums.txt
dfc6d517300687a382557e6d77af1ecb513bdde2e961d01ca46efa008ae15569  pg-exporter_1.3.0-1_amd64.deb
3d2ff642d0bb3657b28eb7c4b30bacc8ef9e4cbd057c870e6ec6817b47ac8092  pg-exporter_1.3.0-1_arm64.deb
4cfe043eb193780515a1e00ab93250dd44ca0728b35cb037ed165c70c89b6b5a  pg-exporter_1.3.0-1_ppc64le.deb
3ae4f8c554242ae52c4ba0fa07a9d95b702f72938ce55e8456dd97242cc46faf  pg_exporter-1.3.0-1.aarch64.rpm
71a0023383170b4ef3c243d9bf08d530b819fa891fa784e87c74b2a55cb426ec  pg_exporter-1.3.0-1.ppc64le.rpm
316a97ccb2df9a02de99dda33826857ec32bbd6fd874ffb950625bc064d62496  pg_exporter-1.3.0-1.x86_64.rpm
4ab312f27f0ded7f0ff5591866a86311d13041fef3a015e92f44fcf4a2284ccd  pg_exporter-1.3.0.darwin-amd64.tar.gz
2b20eb7b46c0790a8524f1c00a22ab57739bd60fd89ee947f6c2ba14e6a0d6bb  pg_exporter-1.3.0.darwin-arm64.tar.gz
7a2a8ce818f30260d1e7267d0b9e1fd5b3cbd569d55ad184fc9d6fb3801f3ad7  pg_exporter-1.3.0.linux-amd64.tar.gz
696619d19efbcf33f4afbae9748e72897289d2b7f772509cd6d465c9e818066d  pg_exporter-1.3.0.linux-arm64.tar.gz
0c16ac4a912f328be90e973b5123a272c2747759be9f56bacb5542653226475e  pg_exporter-1.3.0.linux-ppc64le.tar.gz
aa3724f4e8aeb732de18b7cb416283cbc2e94b9f511ec4b94e703792e8e8b10d  pg_exporter-1.3.0.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.3.0

v1.2.2

v1.2.2 is a routine maintenance release that only refreshes the release toolchain to Go 1.26.2. It does not introduce new collectors, config semantics, or runtime behavior changes.

Highlights

  • Refresh the release toolchain: bump release builds to Go 1.26.2
  • No functional changes: collector behavior, default configs, metric definitions, and runtime semantics remain unchanged

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.2.2/checksums.txt

273dfd45ac367f71044998d19171ee27d7deb094ec9410d4b31aef7caacfdcc6  pg-exporter_1.2.2-1_amd64.deb
5e83c8448ee6350bec96ab95550df439a129c6700e5c9c7d0f9411aa9c2e7f40  pg-exporter_1.2.2-1_arm64.deb
97bb804bd1018c111708df9118561421d2cc51bd47d031b6d1f12cf1c988a3b2  pg-exporter_1.2.2-1_ppc64le.deb
b2f76799b21aba02b6bf5b6e71bf7ae2cf4487ad8817d53aad92f1d710c00120  pg_exporter-1.2.2-1.aarch64.rpm
f0ab38907bc87a9634c22911d8a0501634d58ce34020c0952dd49281a06787e6  pg_exporter-1.2.2-1.ppc64le.rpm
2000593d9d6732f3e03a43e291bc4e2368d2ecea125a2744dc533a030f51c800  pg_exporter-1.2.2-1.x86_64.rpm
e8a71704eb6957beaebd8ecaf83479e44db4a09bd9dc95c32f7b617f141b0386  pg_exporter-1.2.2.darwin-amd64.tar.gz
e648d9444f9a5f3ee49b82bcbbb459eefd73307c789f24f0d5238dbe1bcfec9c  pg_exporter-1.2.2.darwin-arm64.tar.gz
f278aba93d09b2a47aeef66898e770cacfdbc046eab0ba02de29f7c0261d9ede  pg_exporter-1.2.2.linux-amd64.tar.gz
bbeef56452643b8eb6bf9bb5baf113ab2c38177c06f8e1d008e63cce82260801  pg_exporter-1.2.2.linux-arm64.tar.gz
ad2385278ec6060fef2f7db7873c025f56f5c55048b51815cb4195486ca9dbe2  pg_exporter-1.2.2.linux-ppc64le.tar.gz
2ac53298058f09c5569464f918396f13d3a9efebec00296d89497e97ea74caf4  pg_exporter-1.2.2.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.2.2

v1.2.1

v1.2.1 is a lightweight maintenance release focused on release engineering, config package consistency, and documentation/metadata refresh. It does not introduce new collector semantics or runtime behavior changes.

Highlights

  • Refresh the build toolchain: bump both release workflows and Docker build images to Go 1.26.1
  • Standardize config style: switch inline description values in both current and legacy configs to double-quoted form, and regenerate merged pg_exporter.yml / legacy/pg_exporter.yml
  • Add config consistency tests: verify split and merged configs remain equivalent, and check inline metric description style to reduce configuration drift
  • Refresh packaging metadata: update RPM / DEB support descriptions to PostgreSQL 9.x - 18+ and pgBouncer 1.8 - 1.25+, and refresh Pigsty documentation links

Checksums

2cbe7a78a0dde8a6155a543232af883de6623531c9f6ea0951ddc30dc7514649  pg-exporter_1.2.1-1_amd64.deb
e70e09974ad52ba607b176b63c300610e37f44fe67d249aa9ef364bd58352585  pg-exporter_1.2.1-1_arm64.deb
4e6c7fae85e7fe2e62c3d66c388b5f3db57b5e95e85f43ce648d21b792d83d87  pg-exporter_1.2.1-1_ppc64le.deb
30103629e8c5c1ee5589addadb37fcb07b43179c8a19f80c016a0ed8d7ac2a47  pg_exporter-1.2.1-1.aarch64.rpm
01b4dd32b20bca8612f71f0edf3557dfa92fc85f669d3260f627d34ce102b517  pg_exporter-1.2.1-1.ppc64le.rpm
5afb4f14aa71b256cdfc93d6cc6da8a7052427d6f1c1b71900bf2593b196de50  pg_exporter-1.2.1-1.x86_64.rpm
45e71c6017beffabf2873841d374b5de40eb499dd768d6db1208d7cc6295bcf5  pg_exporter-1.2.1.darwin-amd64.tar.gz
d3035cc6a023fe1bad5443a7c1d5c8189b3d807d165f131f88566b5c35476259  pg_exporter-1.2.1.darwin-arm64.tar.gz
14d3f83de4377e5363611d2ae4eef9470a85d7518784c06b8a8c0f63b6e0a340  pg_exporter-1.2.1.linux-amd64.tar.gz
71082081e7aaf1cf15c941c310d03da49cf9971205274aad7dae21a126bc4fe1  pg_exporter-1.2.1.linux-arm64.tar.gz
cba30919b8d2945be199a4a346eb2891c88fd7a1d6c3482c1006442f4f6109e7  pg_exporter-1.2.1.linux-ppc64le.tar.gz
6fe528a242f0bbd3b89cd8b2697f48905b5c4b1398abfb3305193808c01738e9  pg_exporter-1.2.1.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.2.1

v1.2.0

v1.2.0 is a stability-and-compatibility focused minor release across startup flow, hot reload, health probing, config validation, and legacy support.

New Features:

  • Add robust hot reload workflow: support platform-specific reload signals (SIGHUP / SIGUSR1) and strengthen POST /reload to refresh configs and query plans without process restart
  • Switch startup to non-blocking mode: HTTP endpoints come up first even when target precheck fails, making recovery and monitoring integration smoother
  • Add PostgreSQL 9.1-9.6 legacy config bundle: provide legacy/ configs and a make conf9 target for easier onboarding of EOL PostgreSQL versions
  • Rework health probing architecture: use cached health snapshots with periodic probes for more consistent role-based health endpoints and smoother reload behavior
  • Improve release engineering baseline: run go test and go vet in release workflows and bump build toolchain to Go 1.26.0

Bug Fixes:

  • Fix multiple config parsing edge cases: reject malformed metrics entries, return explicit errors when config dirs fail to load valid YAML, and harden runtime fallbacks
  • Fix CLI bool flag parsing to correctly handle --flag=false style arguments
  • Fix /explain output/rendering behavior by adjusting content type handling and using safer template rendering
  • Fix predicate query and PG URL handling details: better BOOL/BOOLEAN predicate support, safer row lifecycle handling, and improved dbname query-parameter parsing/redaction
  • Fix resource cleanup when auto-discovered targets are removed by closing dropped server connections asynchronously
  • Fix metric/label validation details including const-label conflict checks, scaled default-value handling, and Prometheus naming/rule checks

Checksums

26e7a052e730b412bbbe5f49846f951b89650f1f95c2466d5d486923f0825f64  pg-exporter_1.2.0-1_amd64.deb
4ec219135c49708d010af7b8a7553b8008f630574e1d4cfc7642fbf951eefafe  pg-exporter_1.2.0-1_arm64.deb
5b2cc00e2c3e2ffd9eb0ab1a4f5e937dd68f3a69a14423a74d4de3d7cf29283e  pg-exporter_1.2.0-1_ppc64le.deb
d536d41a92e8aa85ae3935715d1bf0463208b1e614eae73543f1472ca8a7e0d4  pg_exporter-1.2.0-1.aarch64.rpm
b7a1daa225f8ca4de6d227e6004330589295d924accd221892ebe14f191fe35c  pg_exporter-1.2.0-1.ppc64le.rpm
28bf7d85862510675c64ff5181d216c6a068a23ffa56dc4bb9e6b82165ff99b5  pg_exporter-1.2.0-1.x86_64.rpm
51c3b3d18089d888a54a6b3e7ecb0620dc0da04c81471a0b7aaa88c1677ddb8c  pg_exporter-1.2.0.darwin-amd64.tar.gz
3ba1c7adea9c926afd3054ba18cc43e665e420a495bfcfd2248242c49a67b077  pg_exporter-1.2.0.darwin-arm64.tar.gz
9e1ec6c15e6b2aaadbe27a27053ee1ec289bdd012c19ca6371de738fa5f8843e  pg_exporter-1.2.0.linux-amd64.tar.gz
9e18849693ccda313979db0a230cb81acfe4199364feb6ce3e72d1a89fbfb809  pg_exporter-1.2.0.linux-arm64.tar.gz
6e28489685d0bd1fdabcb71474f64f559ade199b871666954323bae9dc01465f  pg_exporter-1.2.0.linux-ppc64le.tar.gz
9e9beac619fe2c614a77bc3334bc4b80df9db355bf95845eb4b11674ddad52d9  pg_exporter-1.2.0.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.2.0

v1.1.2

Minor release fixing pg_timeline configuration issue and building with latest go deps

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.1.2/checksums.txt

8cddd57a843914a3145a80a3220bc875047b9bcac0664357c01ba86485436236  pg-exporter_1.1.2-1_amd64.deb
f5b25a8ae5c022867a54c17ba1c6493eba20dcb292340460390289336df24f04  pg-exporter_1.1.2-1_arm64.deb
4da2c287f6717681b25befda0d59a89b9d1b258281ce94f3a6bc21d02f70c83c  pg-exporter_1.1.2-1_ppc64le.deb
b26355f3c1a5b8a147291a51e2d7ada204deed6d52877c146a8b3e499defa5e8  pg_exporter-1.1.2-1.aarch64.rpm
42ef89716ba99dd918b0e9c77ef3236129d613f68bb8ae5929668a5a2596cca5  pg_exporter-1.1.2-1.ppc64le.rpm
a8f4a2d5c7b6701c7bac788a7ed7183b6c4b74a334326cd389f3a695fb77675d  pg_exporter-1.1.2-1.x86_64.rpm
775f5ea3188a6acb1327c001c4ba9a0651424c3bb37d800e6f67972c904c4750  pg_exporter-1.1.2.darwin-amd64.tar.gz
7f2bbcc2db1e16dc78c3edd8e67e20e4ec81f2972c8c37135cba6f6afbf91003  pg_exporter-1.1.2.darwin-arm64.tar.gz
33c34b1f9ef6b6e7615f241a95059a8137a2337a454930b668180a9329d12b98  pg_exporter-1.1.2.linux-amd64.tar.gz
2b91a5818d780e38692ab6446cacb496695e67388676c18012be582e8ddfbdd8  pg_exporter-1.1.2.linux-arm64.tar.gz
adcb5f229f4a5d641f6430b9a2dfb0377a2e4310efad242730867d6cdf5e27ee  pg_exporter-1.1.2.linux-ppc64le.tar.gz
90b7c7e4b2b94936b5faa3cf2d35509b62ebc0d60b3afe1abaaf03efcd415a4a  pg_exporter-1.1.2.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.1.2

v1.1.1

Minor release with new collectors and bug fixes.

New Features:

  • New pg_timeline collector for timeline monitoring
  • New pg_sub_16 collector branch to exclude parallel operations in subscriptions (PostgreSQL 16+ compatibility)

Bug Fixes:

  • Fix: Add coalesce for slotname in pg_recv collector to handle NULL values

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.1.1/checksums.txt

fd5ee96511676fc11b975115a4870ed0c811056519f79ad7f24ab7ec538fa278  pg-exporter_1.1.1-1_amd64.deb
b90a08d16a6e4707d82f8f3ae282cb76acb331de607e7544532fd0b774b7aa27  pg-exporter_1.1.1-1_arm64.deb
163955f59a71da48901ffa26bb2f2db0712d31d8aeb1ab3fa463683f719a6d3a  pg-exporter_1.1.1-1_ppc64le.deb
cf4f8bc12bb8a2d1e55553f891fd31c43324e4348249727972eb44f82cd4e6c8  pg_exporter-1.1.1-1.aarch64.rpm
5a425b2f61f308b32f2d107372830c34eb685bfb312ee787f11877a20f1c4a2e  pg_exporter-1.1.1-1.ppc64le.rpm
23606ccea565368971ac2e7f39766455b507021f09457bcf61db13cb10501a16  pg_exporter-1.1.1-1.x86_64.rpm
ce74624eba92573318f50764cee4f355fa1f35697d209f70a4240f8f9d976188  pg_exporter-1.1.1.darwin-amd64.tar.gz
35fba12521dbdcc54a3792278ed4822e4ca9e951665b5e53dff7c2a0f7014ae3  pg_exporter-1.1.1.darwin-arm64.tar.gz
7699bdef15dd306289645beee8d40a123ca75dc988e46d89cdd75a1c1f650bef  pg_exporter-1.1.1.linux-amd64.tar.gz
f4baba59d27a8eb67f0c5209fed7b9f00f78db796e583cc3487701e7803671c6  pg_exporter-1.1.1.linux-arm64.tar.gz
810c3817c27358fa667714f8bfe8d52840a7ea010035e29547919ccb7c9fa781  pg_exporter-1.1.1.linux-ppc64le.tar.gz
3f6df693b3eb92fdaeaeccf99ea7e5977b2c65028a4f00bdfabbc0405b9f5f93  pg_exporter-1.1.1.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.1.1

v1.1.0

Build with Go 1.25.5 and latest dependencies, collector updates:

Collector Changes:

  • pg_setting: Major refactor for PG10-18 compatibility with missing_ok support
    • Add 13 new metrics: max_parallel_workers, max_parallel_workers_per_gather, max_parallel_maintenance_workers, shared_buffers, maintenance_work_mem, effective_cache_size, fsync, full_page_writes, autovacuum, autovacuum_max_workers, checkpoint_timeout, checkpoint_completion_target, hot_standby, synchronous_commit, io_method
    • Rename work_memory_size to work_mem
    • Change min_version from 9.6 to 10, explicit ::int type casting
  • pg_size: Fix log directory size detection, use logging_collector check instead of path pattern matching
  • pg_table: Performance optimization, replace LATERAL subqueries with JOIN for better query performance; fix tuples and frozenxid metric type from COUNTER to GAUGE; increase timeout from 1s to 2s
  • pg_vacuuming: Add PG17 collector branch with new metrics indexes_total, indexes_processed, dead_tuple_bytes for index vacuum progress tracking
  • pg_query: Increase timeout from 1s to 2s for high-load scenarios
  • pg_io: Fix typo in reuses description (“in reused” -> “is reused”)
  • pg_checkpointer: Fix description for pg_checkpointer_10 (“9.4+” -> “9.4-17”)
  • pg_db_confl: Fix description for pg_db_confl_15 (“9.1 - 16” -> “9.1 - 15”)
  • Format alignment fixes for pg_db, pg_indexing, pg_clustering, pg_backup

Other Changes:

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.1.0/checksums.txt

9c65f43e76213bb8a49d1eab2c76a27d9ab694e67bc79f0ad12769ea362b5ca2  pg-exporter_1.1.0-1_amd64.deb
bcd2cacb4febc5fb92f9eda8e733c161c8c6721416e16ec91a773503241c972d  pg-exporter_1.1.0-1_arm64.deb
2c9d4a9cb06d07af0b6dd9dd6e568af073dc9f6775abde63b45f0aae34d171b1  pg-exporter_1.1.0-1_ppc64le.deb
2934ab5b0fb16dca5a96ec1e8f230e32c72b30ca076b5e5ddf8ec553c821f7b8  pg_exporter-1.1.0-1.aarch64.rpm
3c9955f31ba93532cc7f95ff60b0658f4b6eca6a827710e2f70c0716b34eab43  pg_exporter-1.1.0-1.ppc64le.rpm
9fdefbd8e7660dcb130207901a27762e0a381857ba8cf12b63184744f92dea05  pg_exporter-1.1.0-1.x86_64.rpm
7159002016754309e0ed625a9a48049d21177883fa11d1e448eb7655ceb690cc  pg_exporter-1.1.0.darwin-amd64.tar.gz
7d55ac5cda0b1fd8ffbd5e76b9c1c1784ac8e353104a206caaadce89adda6d65  pg_exporter-1.1.0.darwin-arm64.tar.gz
8211ec24277554b9b1a36920d7865153e21c2621031d3d08f22d94cdd2ddf02f  pg_exporter-1.1.0.linux-amd64.tar.gz
d17ab7f9bf04442e642483d432d005d25bb62e0c9caa73cb7e69ee19eb89b3ae  pg_exporter-1.1.0.linux-arm64.tar.gz
c074aeb345cc30f7b6e16aa153ae3d9a12789e4425987590c3fd77c4e68a40b6  pg_exporter-1.1.0.linux-ppc64le.tar.gz
13d653e2abb023ce9526bdc2815135b82f49c044d237030f3f56b09fb016fcb7  pg_exporter-1.1.0.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.1.0

v1.0.3

  • Build with Go 1.25.4 and latest dependencies
  • Fix #80 Conflict with libpq env variables
  • Change default value of auto-discovery to true by @kadaffy

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.0.3/checksums.txt

7efa1a77dfd5b94813c32c7ac015b1d479b1f04fb958f6b1ed5af333e354d015  pg-exporter_1.0.3-1_amd64.deb
41e18bf18eba2ab90ac371bfb46e9152da9fe628ebd8e26766cac08325eb3b07  pg-exporter_1.0.3-1_arm64.deb
7da8ed738d254c120d42aa51d6137f84e7f4e3188bc764d4f9a1438220363a43  pg-exporter_1.0.3-1_ppc64le.deb
a214b555981156da7b7d248b1f728f8ac88a07ac8f77a66c5d8e43b40670d6b4  pg_exporter-1.0.3-1.aarch64.rpm
d876fc66e208612ebffe3c43dabce88b088d915f92584260d710b85a3a131413  pg_exporter-1.0.3-1.ppc64le.rpm
75f62d314fec50c836c534996c884d25ecea77810ab33e7ba0e9c4b783e775b4  pg_exporter-1.0.3-1.x86_64.rpm
47829a19707284bcee1b8dc47cc7d0172398bb533e6b4043950f787486712769  pg_exporter-1.0.3.darwin-amd64.tar.gz
38b6ccb72315cadea542b1f2a7b7022d0e8d48ffd4ab177bb69a0a909b99af6b  pg_exporter-1.0.3.darwin-arm64.tar.gz
36e8dff84d61a7593ff1fcec567ca4ffeaecd0be2f9eabd227ceac71b12a919a  pg_exporter-1.0.3.linux-amd64.tar.gz
6477e8ef873773a09c4f39a29444f21b5b2c71e717e52ca425bcc8e8e5448791  pg_exporter-1.0.3.linux-arm64.tar.gz
a083b51ebed2b280e2eaa0f19558494e7fa6f122a0a86a1d117206fcd090820c  pg_exporter-1.0.3.linux-ppc64le.tar.gz
a1f9b27b7190f478726d96f270a72d9dc4d3f2bcc3b0326b7c4a2607e62ea588  pg_exporter-1.0.3.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.3

v1.0.2

  • Build with Go 1.25.0 and latest dependencies
  • Dedicate website and homepage: https://exp.pgsty.com
  • Release with goreleaser for more os/arch with CI/CD pipeline:
    • add windows amd64 support
    • add linux ppc64le support

Checksums

https://github.com/pgsty/pg_exporter/releases/download/v1.0.2/checksums.txt

683bf97f22173f2f2ec319a88e136939c2958a1f5ced4f4aa09a1357fc1c44c5  pg-exporter_1.0.2-1_amd64.deb
f62d479a92be2d03211c162b8419f968cea87ceef5b1f25f2bcd390e0b72ccb5  pg-exporter_1.0.2-1_arm64.deb
e1bbfc5a4c1b93e6f92bc7adcb4364583ab763e76e156aa5c979d6d1040f4c7a  pg-exporter_1.0.2-1_ppc64le.deb
f51d5b45448e6bbec3467d1d1dc049b1e16976f723af713c4262541ac55a039c  pg_exporter-1.0.2-1.aarch64.rpm
18380011543674e4c48b2410266b41165974d780cbc8918fc562152ba623939e  pg_exporter-1.0.2-1.ppc64le.rpm
198372d894b9598c166a0e91ca36d3c9271cb65298415f63dbffcf6da611f2bb  pg_exporter-1.0.2-1.x86_64.rpm
cbe7e07df6d180507c830cdab4cf86d40ccd62774723946307b5331d4270477d  pg_exporter-1.0.2.darwin-amd64.tar.gz
20c4a35fa244287766c1d1a19cd2e393b3fa451a96a81e5635401e69bef04b97  pg_exporter-1.0.2.darwin-arm64.tar.gz
d742111185f6a89fff34bfd304b851c8eb7a8e38444f0220786e11ed1934eff1  pg_exporter-1.0.2.linux-amd64.tar.gz
0b1f4c97c1089c4767d92eb22419b8f29c9f46fb90ddfd1e8514cc42dc41054f  pg_exporter-1.0.2.linux-arm64.tar.gz
895083fd2c7fc5409cc1a2dbaaef1e47ac7aa6a3fd5db2359012922d90bcdcc3  pg_exporter-1.0.2.linux-ppc64le.tar.gz
5f751228e7120604af9a482fb70197489fa633c38a0f2b6a3489393fbc6a10aa  pg_exporter-1.0.2.windows-amd64.tar.gz

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.2

v1.0.1

  • Add dockerhub images: pgsty/pg_exporter
  • Bump go dependencies to the latest version, build with go 1.24.5
  • Disable pg_tsdb_hypertable collector by default, since timescaledb catalog is changed.

Checksums

d5e2d6a656eef0ae1b29cd49695f9773  pg_exporter-1.0.1-1.aarch64.rpm
cb01bb78d7b216a235363e9342803cb3  pg_exporter-1.0.1-1.x86_64.rpm
67093a756b04845f69ad333b6d458e81  pg_exporter-v1.0.1.darwin-amd64.tar.gz
2d3fdc10045d1cf494b9c1ee7f94f127  pg_exporter-v1.0.1.darwin-arm64.tar.gz
e242314461becfa99c3978ae72838ab0  pg_exporter-v1.0.1.linux-amd64.tar.gz
63de91da9ef711a53718bc60b89c82a6  pg_exporter-v1.0.1.linux-arm64.tar.gz
718f6afc004089f12c1ca6553f9b9ba5  pg-exporter_1.0.1_amd64.deb
57da7a8005cdf91ba8c1fb348e0d7367  pg-exporter_1.0.1_arm64.deb

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.1

v1.0.0

Add PostgreSQL 18 metrics support

  • new collector branch pg_wal_18:
  • remove write, sync, write_time, sync_time metrics
  • move to pg_stat_io
  • new collector branch pg_checkpointer_18:
  • new metric num_done
  • new metric slru_written
  • new collector branch pg_db_18:
  • new metric parallel_workers_to_launch
  • new metric parallel_workers_launched
  • new collector branch pg_table_18:
  • table_parallel_workers_to_launch
  • table_parallel_workers_launched
  • new collector branch pg_io_18:
  • new series about WAL statistics
  • new metric read_bytes
  • new metric write_bytes
  • new metric extend_bytes
  • remove op_bytes due to fixed value
  • new collector branch pg_vacuuming_18
  • new metric delay_time
8637bc1a05b93eedfbfd3816cca468dd  pg_exporter-1.0.0-1.aarch64.rpm
a28c4c0dcdd3bf412268a2dbff79f5b9  pg_exporter-1.0.0-1.x86_64.rpm
229129209b8e6bc356c28043c7c22359  pg_exporter-v1.0.0.darwin-amd64.tar.gz
d941c2c28301269e62a8853c93facf12  pg_exporter-v1.0.0.darwin-arm64.tar.gz
5bbb94db46cacca4075d4c341c54db37  pg_exporter-v1.0.0.linux-amd64.tar.gz
da9ad428a50546a507a542d808f1c0fa  pg_exporter-v1.0.0.linux-arm64.tar.gz
0fa2395d9d7a43ab87e5c87e5b06ffcc  pg-exporter_1.0.0_amd64.deb
fed56f8a37e30cc59e85f03c81fce3f5  pg-exporter_1.0.0_arm64.deb

https://github.com/pgsty/pg_exporter/releases/tag/v1.0.0

v0.9.0

Default Collectors

  • new metrics collector for timescaledb hypertable
  • new metrics collector for citus dist node
  • new metrics collector for pg_wait_sampling wait event profile
  • pg_slot overhaul: Add 16/17 pg_replication_slot metrics
  • allow pg_slot collector run on replica since 16/17
  • refactor pg_wait collector to agg from all processes
  • restrict pg_clustering, pg_indexing, pg_vacuuming run on primary
  • mark all reset_time as GAUGE rather than COUNTER
  • fix pg_recovery_prefetch_skip_fpw type from GAUGE to COUNTER
  • fix pg_recv.state type from LABEL to GAUGE
  • Format collector in compact mode
  • new default metric pg_exporter_build_info / pgbouncer_exporter_build_info
  • add server_encoding to pg_meta collector
  • add 12 new setting metrics to pg_setting collector
  • wal_block_size
  • segment_size
  • wal_segment_size
  • wal_level
  • wal_log_hints
  • work_mem
  • hugepage_count
  • hugepage_status
  • max_wal_size
  • min_wal_size
  • max_slot_wal_keep_size

Exporter Codebase

  • normalize collector branch name with min pg ver suffix
  • Add license file to binary packages
  • move pgsty/pg_exporter repo to pgsty/pg_exporter
  • refactor server.go to reduce Compatible and PostgresPrecheck complexity
  • rename metrics collector with extra number prefix for better sorting
  • bump dependencies to the latest version
  • execute fatal collectors ahead of all non-fatal collectors, and fail fast

https://github.com/pgsty/pg_exporter/releases/tag/v0.9.0

v0.8.1

https://github.com/pgsty/pg_exporter/releases/tag/v0.8.1

v0.8.0

https://github.com/pgsty/pg_exporter/releases/tag/v0.8.0

v0.7.1

Routine update with dependabot

https://github.com/pgsty/pg_exporter/releases/tag/v0.7.1

v0.7.0

Refactor codebase for the latest go version.

https://github.com/pgsty/pg_exporter/releases/tag/v0.7.0

v0.6.0

https://github.com/pgsty/pg_exporter/releases/tag/v0.6.0

v0.5.0

Exporter Enhancement

  • Build rpm & deb with nfpm
  • Add column.default, replace when metric value is NULL
  • Add column.scale, multiply scale factor when metric value is float/int (e.g µs to second)
  • Fix /stat endpoint output
  • Add docker container pgsty/pg_exporter

Metrics Collector

  • scale bgwriter & pg_wal time unit to second
  • remove pg_class collector and move it to pg_table & pg_inex
  • add pg_class metrics to pg_table
  • add pg_class metrics to pg_index
  • enable pg_table_size by default
  • scale pg_query pg_db pg_bgwriter pg_ssl pgbouncer_stat time metrics to second

https://github.com/pgsty/pg_exporter/releases/tag/v0.5.0

v0.4.1

  • update default collectors
    • omit citus & timescaledb schemas on object monitoring
    • avoid duplicate pg_statio tuples
    • support pgbouncer v1.16
    • bug fix: pg_repl collector overlap on pg 12
  • new parameter: -T connect-timeout PG_EXPORTER_CONNECT_TIMEOUT this can be useful when monitoring remote Postgres instances.
  • now pg_exporter.yaml are renamed as pg_exporter.yml in rpm package.

https://github.com/pgsty/pg_exporter/releases/tag/v0.4.1

v0.4.0

  • Add PG 14 support
  • Default metrics configuration overhaul. (BUT you can still use the old configuration)
  • add auto-discovery , include-database and exclude-database option
  • Add multiple database monitoring implementations (with auto-discovery = on)

https://github.com/pgsty/pg_exporter/releases/tag/v0.4.0

v0.3.2

  • fix shadow DSN corner case
  • fix typo & docs

https://github.com/pgsty/pg_exporter/releases/tag/v0.3.2

v0.3.1

fix default configuration problems (especially for versions lower than 13)

  • setting primary_conninfo not exists until PG13
  • add funcid label to pg_func collector to avoid func name duplicate label
  • fix version string to pg_exporter

https://github.com/pgsty/pg_exporter/releases/tag/v0.3.1

v0.3.0

https://github.com/pgsty/pg_exporter/releases/tag/v0.3.0

  • Change default configuration, Support PostgreSQL 13 new metrics (pg_slru, pg_shmem, pg_query13,pg_backup, etc…)
  • Add a series of new REST APIs for health / recovery status check
  • Add a dummy server with fake pg_up 0 metric, which serves before PgExporter is initialized.
  • Add sslmode=disable to URL if sslmode is not given
  • fix typos and bugs

v0.2.0

  • add yum package and linux service definition
  • add a ‘skip’ flag into query config
  • fix pgbouncer_up metrics
  • add conf reload support

https://github.com/pgsty/pg_exporter/releases/tag/v0.2.0

v0.1.2

  • fix pgbouncer_up metrics
  • add dynamic configuration reload
  • remove ‘shard’ related logic
  • add a ‘bulky’ mode to default settings

https://github.com/pgsty/pg_exporter/releases/tag/v0.1.2

v0.1.1

Fix the bug that pg_exporter will hang during start-up if any query is failed.

https://github.com/pgsty/pg_exporter/releases/tag/v0.1.1

v0.1.0

It works, looks good to me.

https://github.com/pgsty/pg_exporter/releases/tag/v0.1.0

v0.0.4

Tested in real world production environment with 200+ nodes for about 2 weeks. Looks good !

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.4

v0.0.3

v0.0.3 Release, Tested in Production Environment

This version is already tested in a production environment.

This project is still under rapid evolution, I would say if you want use it in production , try with caution.

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.3

v0.0.2

It’s ok to try now

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.2

v0.0.1

Add pgbouncer mode

https://github.com/pgsty/pg_exporter/releases/tag/v0.0.1