Self-hosted service
prometheus-community/postgres_exporter avatar
prometheus-community/postgres_exporter

postgres_exporter's probe endpoint takes your DSN in the URL

A PostgreSQL metric exporter for Prometheus

3,652 stars850 forksGoApache-2.0

At a glance

What is it?
A Prometheus exporter for PostgreSQL with twenty-four collectors, ten of them off by default, where the optional multi-target mode passes a full DSN as a URL query parameter, the page quotes two different ports for the same exporter, and the build produces an image named differently from the one the quick start pulls.
Who is it for?
postgres_exporter is the right tool if you already run Prometheus and want database metrics without changing the database's own logging, and installing it as a sidecar keeps the credential handling out of URLs entirely. Two things to decide before enabling the rest.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • prometheus-community/postgres_exporter3,652 ★ · +30
Star history
Repository2026-09-242026-11-14
prometheus-community/postgres_exporter3.6k3.7k

30 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The probe endpoint takes a DSN as a URL parameter

The multi-target feature works by sending an http request to the endpoint `/probe?target=foo:5432`, where target is set to the DSN of the postgres instance to scrape metrics from. A DSN carries the credentials. The page says so itself, in the next sentence: to avoid putting sensitive information like username and password in the URL, preconfigured auth modules are supported via the `auth_modules` section of the config file, and those can be used with the `/probe` endpoint by specifying the `?auth_module=foo` http parameter. So the mitigation exists and is documented, and the unmitigated form is the one described first. The example Prometheus config wires the endpoint up with three relabel rules, moving the scraped address into `__param_target`, moving that back out into `instance`, and finally overwriting `__address__` with the exporter's own address so every target is scraped through one instance.

yaml
metrics_path: /probe
params:
  auth_module: [foo]
relabel_configs:
  - source_labels: [__address__]
    target_label: __param_target
  - source_labels: [__param_target]
    target_label: instance
  - target_label: __address__
    replacement: 127.0.0.1:9116  # The postgres exporter's real hostname:port.

That `instance` label is what ends up holding the DSN, and it is a label rather than a log line, so it also lands in the time series database. The escape hatch has one type: currently only the `userpass` type is supported, so a shared plaintext password per target is the option, with `options` that become key=value parameters of the DSN, `sslmode: disable` being the example given.

Multi-target is the concession, the sidecar is the recommendation

The framing matters more than the mechanism. The page says this exporter supports the multi-target pattern, which allows running a single instance for multiple postgres targets, and then says using the multi-target functionality is optional and meant for cases where it is impossible to install the exporter as a sidecar, for example SaaS-managed services. So the DSN-in-URL problem belongs to the fallback path, not the default one. What the default path looks like is the quick start: two environment variables, `DATA_SOURCE_USER` and `DATA_SOURCE_PASS`, plus `DATA_SOURCE_URI`, with the docs directory described as covering database permissions, connecting and secrets, and Getting Started covering how to supply the password without putting it in an environment variable. The page points at three credential mechanisms and makes you choose. Separately, the configuration file has its own off switch: the path is set with the `--config.file` command line flag, it defaults to `postgres_exporter.yml`, and setting `--config.file=""` runs the exporter with no configuration file at all.

Ten of twenty-four collectors are off unless you ask

The flags section lists twenty-four collectors, each with a matching `no-` form to switch it off, and each stating its own default. Fourteen are enabled by default: `database`, `locks`, `replication`, `replication_slots`, `settings`, `stat_activity`, `stat_archiver`, `stat_bgwriter`, `stat_database`, `stat_progress_vacuum`, `stat_replication`, `stat_user_tables`, `statio_user_tables` and `wal`. Ten are disabled: `database_wraparound`, `long_running_transactions`, `postmaster`, `process_idle`, `stat_activity_autovacuum`, `stat_checkpointer`, `stat_statements`, `stat_wal_receiver`, `statio_user_indexes` and `xlog_location`. The pattern behind that split is visible in the names. The disabled ten are the ones that cost a scan, expose statement text, or expose internals; the enabled fourteen are counters a server returns cheaply.

One collector can export the text of your SQL

`stat_statements` is disabled by default and carries four flags of its own, which makes it the most configurable collector in the list. `collector.stat_statements.include_query` enables selecting statement query together with queryId, and is disabled by default as well. `collector.stat_statements.query_length` sets the maximum length of the statement text, default 120. `collector.stat_statements.limit` sets the maximum number of statements to return, default 100. `collector.stat_statements.exclude_databases` and `collector.stat_statements.exclude_users` take comma-separated lists to exclude, and both default to none. So turning on query text is two flags deep and nothing is filtered when you do, which is worth knowing before the metrics endpoint becomes part of a shared Prometheus.

The page quotes two ports for the same exporter

The quick start tells you to test with a request to `http://localhost:9187/metrics`, and the Dockerfile declares `EXPOSE 9187`. The Prometheus example config, in the same document, ends its relabel rules with a replacement address of `127.0.0.1:9116`, carrying the comment that this is the postgres exporter's real hostname:port. 9187 and 9116 are both in the visible text and they disagree. 9116 is the well known port for a different Prometheus exporter, the node exporter, which suggests the value was carried across when the config was written. Anyone assembling the multi-target setup by copying that block will point Prometheus at a port nothing in this project listens on, and the failure looks like an exporter that is up and refusing connections rather than a typo.

The build produces a differently named image from the one the page pulls

The Makefile sets `DOCKER_IMAGE_NAME ?= postgres-exporter`, with a hyphen, and `DOCKER_REPO ?= prometheuscommunity`. The page then says the build will produce `prometheuscommunity/postgres_exporter:${branch}`, spelled differently and tagged by branch name rather than by version. The quick start pulls `quay.io/prometheuscommunity/postgres-exporter` from a different registry, while the badge at the top of the page links to a Docker Hub tags page. So the image lives in two registries under two names and gets a branch name as its tag. Four architectures are cross-built, and the Makefile says so in the variable the shared include reads.

code
promu crossbuild -p linux/amd64 -p linux/armv7 -p linux/arm64 -p linux/ppc64le

The Makefile also opens with a comment explaining that `all` has to be defined before including `Makefile.common`, otherwise it becomes the first target from that include, and then sets `DOCKER_ARCHS ?= amd64 armv7 arm64 ppc64le`. So the build is a thin wrapper over Prometheus's shared makefile rather than a self contained one. The Dockerfile itself is short: it declares `ARG ARCH` and `ARG OS` once before the `FROM` line for the base image and once again after it for the copy path, copies the binary out of `.build/`, copies `LICENSE` and `NOTICE` alongside it, and runs as `USER nobody`.

Three YAML modules and two testing approaches in one manifest

The module declares `go 1.26.0` and twelve direct requirements. Among them three YAML modules appear across two import paths: `gopkg.in/yaml.v2`, `gopkg.in/yaml.v3` and, as an indirect dependency, `go.yaml.in/yaml/v2`. That last one is the relocated path for the same v2 library, so the same code is reachable under two module identities. Testing brings its own duplication: `github.com/DATA-DOG/go-sqlmock` for faking database connections, `github.com/smartystreets/goconvey` for the assertion style, and `gopkg.in/check.v1` as a third framework in the direct list. The rest is conventional Prometheus furniture, `prometheus/client_golang`, `prometheus/common` and `prometheus/exporter-toolkit`, plus `lib/pq` as the driver and `alecthomas/kingpin/v2` for flag parsing.

The metric queries live in a YAML file beside a mixin directory

Several root entries explain what the repository actually is. There is `queries.yaml`, a `postgres_mixin/` directory, and a script called `postgres-metrics-get-changes.sh`, which together say the metric definitions are declarative data in a mixin compatible layout and that fetching changes to them is a scripted operation. Two more GitHub facing scripts sit alongside, `gh-assets-clone.sh` and `gh-metrics-push.sh`. Then there is `postgres_exporter.rc`, which reads like an init script for a process supervisor, `postgres_exporter_integration_test_script` with no extension, an `AGENTS.md`, and a `VERSION` file, so the version lives in the tag, in the release title and in a file on disk. Build configuration is split three ways as well, with `.promu.yml`, `.golangci.yml` and `.yamllint`.

Editorial conclusion

postgres_exporter is the right tool if you already run Prometheus and want database metrics without changing the database's own logging, and installing it as a sidecar keeps the credential handling out of URLs entirely. Two things to decide before enabling the rest. The multi-target mode is documented as a concession for cases where a sidecar is impossible, and its default form puts a DSN into a query parameter, so on a shared Prometheus the target label ends up holding credentials. And the stat_statements collector can export the text of your SQL when you turn on a separate include-query flag, with no default exclusion of databases or users.

Frequently asked questions

what is postgres exporter

A Prometheus exporter for PostgreSQL server metrics. It exposes a metrics endpoint on port 9187, and the page says CI has tested PostgreSQL versions 13, 14, 15, 16, 17 and 18. User documentation lives in the docs directory, covering getting started, Docker images, configuration, database permissions, connecting and secrets.

how to install postgres exporter

Via Docker: start an example database, then run quay.io/prometheuscommunity/postgres-exporter with DATA_SOURCE_URI, DATA_SOURCE_USER and DATA_SOURCE_PASS set. Or build from source with git clone, make build and then run ./postgres_exporter with its flags. Getting Started covers the other installation routes.

How do I scrape several databases with one postgres_exporter?

Through the multi-target pattern: a single exporter instance, scraped at the /probe endpoint with the target parameter set to the DSN of the instance to scrape. Credentials are kept out of that URL by declaring an auth_modules entry in the config file and passing ?auth_module=foo instead. Only the userpass type is currently supported, and its options become key=value DSN parameters.

How do I keep postgres_exporter from publishing my SQL text?

The stat_statements collector is disabled by default. If you enable it, collector.stat_statements.include_query is a separate flag, also disabled by default, and turning it on selects statement text alongside the query id. There are flags to cap the text length at 120 characters, cap the number of statements at 100, and exclude whole databases or whole users, and none of those exclusions is set by default.

Which postgres_exporter collectors are enabled by default?

There are twenty-four collectors and ten are disabled by default: database_wraparound, long_running_transactions, postmaster, process_idle, stat_activity_autovacuum, stat_checkpointer, stat_statements, stat_wal_receiver, statio_user_indexes and xlog_location. Every collector has a matching no- prefixed flag to switch it off, and each flag states its own default on the page.

Does postgres_exporter need a config file?

No. The config file path is set with --config.file, defaults to postgres_exporter.yml, and setting --config.file to an empty value runs the exporter without one. The file holds the auth_modules section used by the multi-target probe endpoint, where each module has a type and, for userpass, a username, a password and options that become DSN key=value parameters.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. prometheus-community/postgres_exporter on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/prometheus-community-postgres-exporter.svg)](https://hysenlabs.com/projects/prometheus-community-postgres-exporter)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/prometheus-community-postgres-exporter.svg)](https://hysenlabs.com/projects/prometheus-community-postgres-exporter)

Was this useful?