---
title: PostgreSQL NRDOT metrics reference
source: https://docs.newrelic.com/docs/opentelemetry/database/postgresql/metrics-reference
---

> #### 💡 PREVIEW
>
> We're still working on this feature, but we'd love for you to try it out!
>
> This feature is currently provided as part of a preview pursuant to our [pre-release policies](https://docs.newrelic.com/docs/licenses/license-information/referenced-policies/new-relic-pre-release-policy/).

The NRDOT Collector reports a wide range of PostgreSQL metrics. New Relic collects the metrics in [Default metrics](#default) automatically. For deeper insight into performance and health, enable any of the metrics listed in [Additional metrics](#additional).

> #### 💡 TIP
>
> Each metric is scoped to a specific database, table, schema, or index. This context is set on the resource, not as a metric attribute.

**Default metrics**

These metrics are collected automatically and power the New Relic UI, including the out-of-the-box dashboard.

| Metric                                  | Description                                                                                                                                 | Unit            | Type                                 | Attributes                                                         |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------------------------ | ------------------------------------------------------------------ |
| `postgresql.backends`                   | Number of backend connections                                                                                                               | `1`             | sum (cumulative, int)                | —                                                                  |
| `postgresql.bgwriter.buffers.allocated` | Number of allocated buffers                                                                                                                 | `{buffers}`     | sum (cumulative, int, monotonic)     | —                                                                  |
| `postgresql.bgwriter.buffers.writes`    | Number of written buffers                                                                                                                   | `{buffers}`     | sum (cumulative, int, monotonic)     | `bg_buffer_source` (backend, backend_fsync, checkpoints, bgwriter) |
| `postgresql.bgwriter.checkpoint.count`  | Number of checkpoints performed                                                                                                             | `{checkpoints}` | sum (cumulative, int, monotonic)     | `bg_checkpoint_type` (requested, scheduled)                        |
| `postgresql.bgwriter.duration`          | Total time spent on writing and syncing files to disk by checkpoints                                                                        | `ms`            | sum (cumulative, double, monotonic)  | `bg_duration_type` (sync, write)                                   |
| `postgresql.bgwriter.maxwritten`        | Number of times the background writer stopped a cleaning scan because it had already written too many buffers                               | `1`             | sum (cumulative, int, monotonic)     | —                                                                  |
| `postgresql.blocks_read`                | Number of blocks read                                                                                                                       | `1`             | sum (cumulative, int, monotonic)     | `source`                                                           |
| `postgresql.commits`                    | Number of commits                                                                                                                           | `1`             | sum (cumulative, int, monotonic)     | —                                                                  |
| `postgresql.connection.max`             | Maximum number of client connections allowed                                                                                                | `{connections}` | gauge (int)                          | —                                                                  |
| `postgresql.database.count`             | Number of user databases                                                                                                                    | `{databases}`   | sum (cumulative, int, non-monotonic) | —                                                                  |
| `postgresql.db_size`                    | Database disk usage                                                                                                                         | `By`            | sum (cumulative, int, non-monotonic) | —                                                                  |
| `postgresql.index.scans`                | Number of index scans on a table                                                                                                            | `{scans}`       | sum (cumulative, int, monotonic)     | —                                                                  |
| `postgresql.index.size`                 | Size of the index on disk                                                                                                                   | `By`            | gauge (int)                          | —                                                                  |
| `postgresql.operations`                 | Number of database row operations                                                                                                           | `1`             | sum (cumulative, int, monotonic)     | `operation` (ins, upd, del, hot_upd)                               |
| `postgresql.replication.data_delay`     | Amount of data delayed in replication                                                                                                       | `By`            | gauge (int)                          | `replication_client`                                               |
| `postgresql.rollbacks`                  | Number of rollbacks                                                                                                                         | `1`             | sum (cumulative, int, monotonic)     | —                                                                  |
| `postgresql.rows`                       | Number of rows in the database                                                                                                              | `1`             | sum (cumulative, int, non-monotonic) | `state` (dead, live)                                               |
| `postgresql.table.count`                | Number of user tables in a database                                                                                                         | `{table}`       | sum (cumulative, int, non-monotonic) | —                                                                  |
| `postgresql.table.size`                 | Disk space used by a table                                                                                                                  | `By`            | sum (cumulative, int, non-monotonic) | —                                                                  |
| `postgresql.table.vacuum.count`         | Number of times a table was manually vacuumed                                                                                               | `{vacuum}`      | sum (cumulative, int, monotonic)     | —                                                                  |
| `postgresql.wal.age`                    | Age of the oldest WAL file. Requires WAL enabled with at least one replica                                                                  | `s`             | gauge (int)                          | —                                                                  |
| `postgresql.wal.lag`                    | Time between flushing recent WAL locally and receiving notification the standby completed an operation. Requires WAL + at least one replica | `s`             | gauge (int)                          | `wal_operation_lag` (flush, replay, write), `replication_client`   |

## Additional metrics [#additional]

The following metrics are disabled by default but can be enabled for deeper insights into PostgreSQL performance and health. These metrics are organized by functionality.

**Dashboard metrics**

The out-of-the-box PostgreSQL entity dashboard uses the following additional metrics that must be explicitly enabled:

| Metric                        | Description                                                                 | Unit                | Dashboard widget               | Extra requirements                                     |
| ----------------------------- | --------------------------------------------------------------------------- | ------------------- | ------------------------------ | ------------------------------------------------------ |
| `postgresql.database.locks`   | Number of database locks                                                    | `{lock}`            | Database Locks by Mode/Type    | —                                                      |
| `postgresql.deadlocks`        | Number of deadlocks                                                         | `{deadlock}`        | Deadlocks                      | —                                                      |
| `postgresql.function.calls`   | Calls made to a function                                                    | `{call}`            | Function Calls/min             | Requires `track_functions=pl|all` in `postgresql.conf` |
| `postgresql.query.conflicts`  | Queries canceled due to recovery conflicts. Standby-only; zero on primaries | `{query}`           | Query Conflicts                | —                                                      |
| `postgresql.sequential_scans` | Number of sequential scans                                                  | `{sequential_scan}` | Sequential Scans/min           | —                                                      |
| `postgresql.temp.io`          | Total data written to temporary files by queries                            | `By`                | Temp Files & Temp I/O (MB/min) | —                                                      |
| `postgresql.temp_files`       | Number of temporary files                                                   | `{temp_file}`       | Temp Files & Temp I/O (MB/min) | —                                                      |

**Database activity metrics**

Additional database activity metrics not used by the dashboard:

| Metric                            | Description                                                                             | Unit             | Attributes |
| --------------------------------- | --------------------------------------------------------------------------------------- | ---------------- | ---------- |
| `postgresql.blks_hit`             | Disk blocks found already in the buffer cache                                           | `{blks_hit}`     | —          |
| `postgresql.blks_read`            | Disk blocks read in this database                                                       | `{blks_read}`    | —          |
| `postgresql.tup_fetched`          | Rows fetched by queries in the database                                                 | `{tup_fetched}`  | —          |
| `postgresql.tup_returned`         | Rows returned by queries in the database                                                | `{tup_returned}` | —          |
| `postgresql.tup_inserted`         | Rows inserted by queries in the database                                                | `{tup_inserted}` | —          |
| `postgresql.tup_updated`          | Rows updated by queries in the database                                                 | `{tup_updated}`  | —          |
| `postgresql.tup_deleted`          | Rows deleted by queries in the database                                                 | `{tup_deleted}`  | —          |
| `postgresql.query.execution.time` | Total execution time of SQL statements tracked by `pg_stat_statements` for the database | `s`              | —          |

**Advanced metrics**

| Metric                 | Description                                                                                       | Unit | Attributes                                |
| ---------------------- | ------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------- |
| `postgresql.wal.delay` | Precise replacement for `wal.lag`, behind the `postgresqlreceiver.preciselagmetrics` feature gate | `s`  | `wal_operation_lag`, `replication_client` |

**Vector metrics (pgvector extension)**

Vector similarity search metrics require PostgreSQL 13+ and the `pg_stat_statements` and `pgvector` extensions:

| Metric                                   | Description                                                       | Unit        | Attributes                          |
| ---------------------------------------- | ----------------------------------------------------------------- | ----------- | ----------------------------------- |
| `postgresql.vector.search.calls`         | Vector similarity search executions, grouped by distance function | `{search}`  | `postgresql.distance.function.name` |
| `postgresql.vector.search.duration`      | Cumulative execution time of vector searches                      | `s`         | `postgresql.distance.function.name` |
| `postgresql.vector.search.rows_returned` | Cumulative rows returned by vector searches                       | `{rows}`    | `postgresql.distance.function.name` |
| `postgresql.vector.insert.rows`          | Vectors inserted into pgvector tables                             | `{vectors}` | —                                   |
| `postgresql.vector.insert.duration`      | Cumulative execution time of pgvector inserts                     | `s`         | —                                   |

## Query events [#query-events]

The following events are disabled by default but can be enabled to collect query-level telemetry data.

**Query sample events**

Real-time visibility into currently-running database statements — a point-in-time snapshot taken every scrape, not a complete execution log. This event is disabled by default and requires the monitoring user to hold `pg_monitor`.

| Attribute                                                         | Description                                                                                                                                                                      |
| ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `db.system.name`                                                  | Name of the database. This is always `postgresql`                                                                                                                                |
| `db.query.text`                                                   | The SQL statement text                                                                                                                                                           |
| `db.query.comment_tags` / `.nr_service_guid`                      | APM-correlation comment tags. For more information, refer to [Link your PostgreSQL database with APM](https://docs.newrelic.com/docs/opentelemetry/database/capabilities/db-apm) |
| `db.query.text.normalized.hash`                                   | MD5 of normalized SQL for cross-engine correlation                                                                                                                               |
| `user.name`                                                       | User logged into this backend                                                                                                                                                    |
| `postgresql.state`                                                | Current overall state of the backend                                                                                                                                             |
| `postgresql.pid`                                                  | Process ID of this backend                                                                                                                                                       |
| `postgresql.backend_start`                                        | UTC (RFC3339) timestamp the backend/connection started. Stable for the connection's lifetime, unlike `postgresql.query_start` which changes every query                          |
| `postgresql.session_duration`                                     | Whole seconds since backend start. `0` if `backend_start` unavailable                                                                                                            |
| `postgresql.application_name`                                     | Name of the connected application                                                                                                                                                |
| `network.peer.address` / `network.peer.port`                      | Client IP address / TCP port                                                                                                                                                     |
| `postgresql.client_hostname`                                      | Reverse-DNS hostname of the client                                                                                                                                               |
| `postgresql.query_start`                                          | When the currently active (or last) query started                                                                                                                                |
| `postgresql.wait_event` / `.wait_event_type`                      | Wait event name / category, if the backend is currently waiting                                                                                                                  |
| `postgresql.query_id`                                             | Identifier of this backend's most recent query                                                                                                                                   |
| `postgresql.total_exec_time`                                      | Query duration in delta milliseconds                                                                                                                                             |
| `postgresql.blocking.pids`                                        | Array of PIDs blocking this session. Empty when not blocked                                                                                                                      |
| `postgresql.blocking.start_time`                                  | UTC timestamp when the current lock wait began. Empty when not blocked                                                                                                           |
| `postgresql.blocking.wait_duration`                               | Whole seconds waited for a lock. `0` when not blocked                                                                                                                            |
| `postgresql.blocking.lock.mode` / `.lock.type` / `.lock.relation` | Lock mode / resource type / relation name being waited on. Empty when not blocked                                                                                                |
| `postgresql.blocking.transaction.start_time`                      | UTC timestamp when the current transaction started. Empty when no active transaction                                                                                             |

**Top query events**

Aggregated per-normalized-query execution stats from `pg_stat_statements`, reported as **incremental (delta) values** since the last collection cycle. This event is disabled by default and requires the `pg_stat_statements` extension in every scanned database.

| Attribute                                                        | Description                                                                                                                                                                                                  |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `db.system.name`                                                 | Name of the database. This is always `postgresql`                                                                                                                                                            |
| `db.query.text`                                                  | The SQL statement text (normalized, `$1`/`$2` placeholders)                                                                                                                                                  |
| `db.query.comment_tags` / `.nr_service_guid`                     | Same as `query_sample`. **Note:** reflects whichever caller ran _first_ — `pg_stat_statements` hashes `queryid` from query structure only and freezes the stored text (comments included) at first execution |
| `db.query.text.normalized.hash`                                  | MD5 of normalized SQL for cross-engine correlation                                                                                                                                                           |
| `postgresql.calls` / `.rows`                                     | Times executed / rows retrieved-affected, delta values                                                                                                                                                       |
| `postgresql.shared_blks_dirtied` / `.hit` / `.read` / `.written` | Shared block activity, delta values                                                                                                                                                                          |
| `postgresql.temp_blks_read` / `.written`                         | Temp block activity, delta values                                                                                                                                                                            |
| `postgresql.queryid`                                             | Hash identifying identical normalized queries                                                                                                                                                                |
| `postgresql.rolname`                                             | Role that executed the query                                                                                                                                                                                 |
| `postgresql.total_exec_time` / `.total_plan_time`                | Total execution / planning time, delta milliseconds                                                                                                                                                          |
| `postgresql.query_plan`                                          | The EXPLAIN plan for the statement, if obtainable — see EXPLAIN mechanics below                                                                                                                              |

#### Execution plan collection (EXPLAIN) mechanics

-   **Rate limiting:** `top_query_collection.max_explain_each_interval` (default 1000) caps EXPLAINs per scrape.
-   **Caching:** `query_plan_cache_size` / `query_plan_cache_ttl` (default 1000 entries / 1h) cache a plan once obtained, keyed by query ID.
-   **PostgreSQL 12+ requirement:** parameterized-query EXPLAIN needs `plan_cache_mode = force_generic_plan` before `PREPARE`/`EXPLAIN EXECUTE` — only available on PostgreSQL 12+. On older servers the receiver detects the version and skips EXPLAIN for that query rather than sending a `SET` that would fail.
-   **Privilege boundary:** by default, EXPLAIN runs directly as the monitoring user, and Postgres checks table privileges at _plan_ time — so row-locking or write statements fail with `permission denied` unless granted write access, which the monitoring user should never have. Use `explain_function_name` (see [EXPLAIN plan permissions](https://docs.newrelic.com/docs/opentelemetry/database/postgresql/explain-permissions)) to work around this without granting write access.
-   If a plan can't be obtained for any reason, `postgresql.query_plan` is simply empty for that row — no error surfaced.

## Related documentation [#related]

[Instrumentation in self-hosted environments](https://docs.newrelic.com/docs/opentelemetry/database/postgresql/hosted)

Learn how to set up PostgreSQL monitoring in self-hosted environments with New Relic.

[Instrumentation in RDS environments](https://docs.newrelic.com/docs/opentelemetry/database/postgresql/rds)

Learn how to set up PostgreSQL monitoring in RDS environments with New Relic.

[Troubleshooting guide](https://docs.newrelic.com/docs/opentelemetry/database/postgresql/troubleshooting)

Learn how to troubleshoot common issues with PostgreSQL monitoring.
