PostgreSQL pg_stat_statements Does Not Exist
The relation "pg_stat_statements" does not exist error occurs when an application or monitoring tool queries the pg_stat_statements view but the extension hasn’t been installed in the database. The extension ships with PostgreSQL but requires explicit configuration in shared_preload_libraries, a Postgres restart, and CREATE EXTENSION in each target database to be available.
shared_preload_libraries, restart Postgres, run CREATE EXTENSION in each target database. Managed providers (RDS, Aurora, Supabase) need the parameter-group change to be applied via reboot. The most common mistake is doing steps 1 or 3 but forgetting the others — Postgres will silently behave as if nothing changed.
- pg_stat_statements
- A Postgres contrib extension that tracks execution statistics for each unique SQL statement — call count, total time, mean time, rows returned. The standard data source for query-performance monitoring in any APM tool.
- shared_preload_libraries
- A Postgres configuration parameter listing shared libraries to preload at server start. Changes require a Postgres restart to take effect.
- CREATE EXTENSION
- The SQL command that loads an extension into a specific database. Per-database — running it in
postgresdoesn’t enable it inmy_app. - contrib
- The collection of optional Postgres extensions shipped alongside the core server. Most are installed by default in the contrib package but require explicit enablement to be active.
- Parameter group (RDS/Aurora)
- AWS-managed configuration bundle for RDS/Aurora instances. Changes to
shared_preload_librarieshappen here, not directly inpostgresql.conf.
pg_stat_statements (an extension you have to install) is distinct from pg_stat_activity (a built-in view, always available, shows currently-running queries) and other pg_stat_* views like pg_stat_database, pg_stat_user_tables — those are part of core Postgres and don’t require the extension. The error specifically tells you about pg_stat_statements, the historical aggregation view.
What does this error look like?
Two common surfaces:
From application code or monitoring tool querying the view directly:
ERROR: relation "pg_stat_statements" does not exist
LINE 1: SELECT query, calls, total_exec_time, mean_exec_time FROM pg_stat_statements
^
SQLSTATE: 42P01 (undefined_table)
From a Postgres collector / health check:
WARN collector health check: failed to list query stats {
"err": "ERROR: relation \"pg_stat_statements\" does not exist (SQLSTATE 42P01)"
}
Both come from the same root cause: the view doesn’t exist in the database being queried. Often surfaces the first time you connect a monitoring tool to a database that wasn’t provisioned with the extension.
Why does this happen?
pg_stat_statements is a Postgres contrib extension — meaning it’s shipped with Postgres but not auto-enabled. To use it, three things must all be true:
- The contrib package is installed on the Postgres server. This is usually true on managed providers and in most distros, but worth verifying with
SELECT * FROM pg_available_extensions WHERE name = 'pg_stat_statements'. shared_preload_librariesincludespg_stat_statements— and Postgres has been restarted since this was added. This is the step most people miss; without it, the extension can’t be loaded.- The extension is created in the target database via
CREATE EXTENSION pg_stat_statements. Extensions are per-database. Creating it inpostgresdoes not enable it in your application’s database.
The most common failure mode: someone runs CREATE EXTENSION but skipped the shared_preload_libraries step. The CREATE EXTENSION succeeds — but the extension isn’t actually loaded, so queries against pg_stat_statements still fail. Or vice versa: shared_preload_libraries is configured but CREATE EXTENSION was forgotten.
How severe is this?
| Context | Severity | Reasoning |
|---|---|---|
| APM / monitoring tool depends on it | Major | Query-performance visibility goes dark; slow-query investigation becomes guesswork |
| One-off DBA script needs it | Minor | Easy workaround — install for the investigation, no production impact |
| Application code queries it directly | Major | Application errors out; user-visible if it’s in a hot path |
| Postgres core functionality | None | Postgres itself doesn’t need it — all standard queries work fine |
How to install and fix
1. Confirm the extension is actually missing
SELECT * FROM pg_available_extensions WHERE name = 'pg_stat_statements';
Three possible outcomes:
- No rows returned: the contrib package isn’t installed on the server. Install
postgresql-contrib(or your distro’s equivalent) on self-hosted; contact your managed provider on RDS/Aurora/etc. - Row returned,
installed_versionis null: available but not loaded. Continue to step 2. - Row returned with
installed_version: extension IS installed in this database. Your error is likely a permissions issue or you’re connected to the wrong database.
2. Add to shared_preload_libraries
On self-hosted Postgres, edit postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'
If you already have other libraries listed, append:
shared_preload_libraries = 'pg_stat_statements,timescaledb,pg_cron'
3. Restart PostgreSQL
The shared_preload_libraries change requires a restart — reload isn’t enough.
sudo systemctl restart postgresql
Verify after restart:
SHOW shared_preload_libraries;
4. Run CREATE EXTENSION in each target database
\c my_app_db
CREATE EXTENSION pg_stat_statements;
Critical: do this in every database where you want query stats. Extensions are per-database, not per-cluster. A common mistake when adding new databases later.
5. Grant access to the monitoring user (Postgres 10+)
If your monitoring tool uses a non-superuser, it needs explicit access:
GRANT pg_read_all_stats TO monitoring_user;
Without this grant, queries against pg_stat_statements appear to succeed but return zero rows for non-superusers.
6. Verify with a test query
SELECT count(*) FROM pg_stat_statements;
Non-zero count confirms the extension is loaded and capturing. If the count is zero, run a few SELECT queries against your tables and re-check — pg_stat_statements only records queries executed after it loaded.
Managed Postgres specifics
Each managed Postgres provider requires slightly different setup for shared_preload_libraries:
| Provider | How to add to shared_preload_libraries | Restart needed? |
|---|---|---|
| Amazon RDS | Edit DB parameter group → add pg_stat_statements to shared_preload_libraries | Yes — reboot the DB instance |
| Amazon Aurora | DB cluster parameter group → same field | Yes — reboot |
| Google Cloud SQL | Edit instance flags → add cloudsql.enable_pg_stat_statements=on | Yes — restart instance |
| Azure Database for PostgreSQL | Server parameters → set pg_stat_statements.track=all + shared_preload_libraries already includes it by default on Flexible Server | Yes |
| Supabase | Already enabled by default. CREATE EXTENSION pg_stat_statements in your project’s DB if missing | Usually no — already loaded |
| Heroku Postgres | Available on Standard tier and above. CREATE EXTENSION in your database | No — managed |
| Neon, Crunchy, Render | Usually enabled or trivially toggleable in dashboard | Varies |
The pattern across managed providers: shared_preload_libraries is configured at the platform layer (parameter group, instance flag), not directly. Always check the provider’s docs for the exact UI path — the underlying Postgres mechanism is the same, the management surface differs.
How Dstl8 detects this
Dstl8’s data-source collector surfaces missing-extension errors immediately when connecting to a new Postgres source. Here’s an actual detection from a Dstl8 customer’s onboarding flow (anonymized):
Three details to notice:
- The incident title is exact-match for the SQL error. Engineers searching the literal error string land directly here — both in your logs and in Google.
- The recommended remediation is specific. Not “investigate” — actual fix steps in the right order (shared_preload_libraries first, then CREATE EXTENSION). Saves the on-call from rediscovering the gotcha.
- The downstream impact is named. “Query-performance monitoring unavailable for this source” — explains why this matters, not just that an error happened.
Related patterns
References
- PostgreSQL: pg_stat_statements documentation
- AWS RDS: Working with the pg_stat_statements extension
- Google Cloud SQL: Configuring database flags
- Supabase: Database extensions
Catch missing-extension errors the moment they hit your Postgres source.
Dstl8 surfaces specific SQL errors with named remediation steps — including the gotchas around shared_preload_libraries and managed Postgres providers.














