Database health snapshot
pg_healthCheck PostgreSQL health: connection usage vs max_connections, active queries with wait events, database stats, and table count to identify connection pressure, runaway queries, and lock/IO waits.
Instructions
Quick health snapshot: server version, database size, connection counts measured against max_connections, active queries with their wait events, a pg_stat_database rollup, and table count. Useful as a connection sanity check and to spot runaway queries, connection-cap pressure, and lock/IO waits.
connections:
totalfor the CURRENT database, broken down intoactive/idle/idle_in_transaction/idle_in_transaction_aborted/other(starting, fastpath function call, disabled) /state_unavailable-- those six sum tototal.idle_in_transaction_abortedis called out separately because it holds locks and blocks vacuum while doing no work and will never commit.state_unavailablecounts sessions whosestatereads NULL because the role lacks pg_read_all_stats / pg_monitor membership; a non-zero value means every other bucket is under-counted by at least that much, so do NOT readactive: 0next to it as an idle database. Pluscluster_client_backends(client backends across ALL databases -- those are what actually consume connection slots),max_connections,superuser_reserved_connections, andused_fraction(cluster_client_backends / max_connections). A raw connection count means nothing without the cap; readused_fractionfirst.active_queries:
pid,state,query,application_name,backend_type,wait_event_type/wait_event(both NULL when the backend is running rather than waiting -- the single most diagnostic pair in pg_stat_activity). Both are reported verbatim as the server spells them, and that spelling changes between majors: a backend waiting on a buffer pin reportswait_event_type'BufferPin' through PostgreSQL 18 and 'Buffer' from 19 on, with thewait_eventnames beneath it changing to match. Read them against the reportedversionrather than hard-coding a literal.duration_seconds(since query_start) andtransaction_age_seconds(since xact_start). A large transaction_age_seconds next to a small duration_seconds is a long-open transaction, the usual root cause behind lock waits, bloat, and stalled autovacuum.database_stats: pg_stat_database for the current database --
deadlocks,temp_files/temp_bytes(work_mem spills),conflicts(recovery conflicts, only ever non-zero on a replica),blks_hit/blks_read/cache_hit_ratio, andstats_reset. Every counter is CUMULATIVE since stats_reset, not a rate -- interpret them against that timestamp. Sub-queries that fail (several of these are permission-gated on managed providers) append to_warningsand leave their field null; the rest of the snapshot still returns.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| activeQueryLimit | No | Max active queries to return (default 10, max 100). |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| version | No | Full `version()` banner. Absent (with a `_warnings` entry) if the row came back without it. | |
| database | No | ||
| _warnings | No | ||
| connected | Yes | Always true on a success response -- the version probe answered. | |
| connections | No | ||
| table_count | No | User tables and partitioned tables, as a decimal string. | |
| active_queries | Yes | Empty array both when nothing is running and when the fetch failed -- check `_warnings`. | |
| database_stats | Yes | Null when pg_stat_database is unreadable OR has no row for this database. |