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.














