Free PostgreSQL tool
A cautious PostgreSQL health check—without connecting your database
Run a bounded SELECT-only script, paste its versioned JSON result, and review deterministic findings locally in your browser. No login or database connection is required.
Private by default
Manual results are parsed and analyzed only on this device. If you choose a connected database while signed in, DatabaseMeter runs the same fixed read-only diagnostic through your saved encrypted connection and returns the bounded result without saving the health report.
Step 1
Copy the SELECT-only script
Run it in the database you want to inspect. It returns one versioned JSON object and reads bounded catalog and statistics views only.
Preview script
WITH
database_stats AS (
SELECT
pg_database_size(current_database())::double precision AS database_bytes,
stats_reset
FROM pg_catalog.pg_stat_database
WHERE datname = current_database()
),
relation_stats AS (
SELECT
schemaname::text AS schema_name,
relname::text AS relation_name,
pg_table_size(relid)::double precision AS table_bytes,
pg_indexes_size(relid)::double precision AS index_bytes,
pg_total_relation_size(relid)::double precision AS total_bytes,
COALESCE(n_live_tup, 0)::double precision AS estimated_live_rows,
COALESCE(n_dead_tup, 0)::double precision AS estimated_dead_rows,
COALESCE(seq_scan, 0)::double precision AS seq_scan,
COALESCE(seq_tup_read, 0)::double precision AS seq_tup_read,
COALESCE(idx_scan, 0)::double precision AS idx_scan,
last_vacuum,
last_autovacuum,
last_analyze,
last_autoanalyze
FROM pg_catalog.pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC, schemaname, relname
LIMIT 100
),
index_stats AS (
SELECT
schemaname::text AS schema_name,
relname::text AS relation_name,
indexrelname::text AS index_name,
pg_relation_size(indexrelid)::double precision AS index_bytes,
COALESCE(idx_scan, 0)::double precision AS idx_scan,
COALESCE(idx_tup_read, 0)::double precision AS idx_tup_read,
COALESCE(idx_tup_fetch, 0)::double precision AS idx_tup_fetch
FROM pg_catalog.pg_stat_user_indexes
ORDER BY pg_relation_size(indexrelid) DESC, schemaname, indexrelname
LIMIT 150
),
connection_stats AS (
SELECT
current_setting('max_connections')::integer AS max_connections,
count(*)::integer AS total,
count(*) FILTER (WHERE state = 'active')::integer AS active,
count(*) FILTER (WHERE state = 'idle')::integer AS idle,
count(*) FILTER (WHERE state = 'idle in transaction')::integer AS idle_in_transaction,
count(*) FILTER (WHERE wait_event_type IS NOT NULL)::integer AS waiting,
count(*) FILTER (WHERE state = 'active' AND query_start < clock_timestamp() - interval '5 minutes')::integer AS long_running,
count(*) FILTER (WHERE xact_start < clock_timestamp() - interval '5 minutes')::integer AS long_transaction
FROM pg_catalog.pg_stat_activity
WHERE datname = current_database()
AND pid <> pg_backend_pid()
)
SELECT jsonb_build_object(
'schema_version', 'databasemeter-health-v1',
'generated_at', clock_timestamp(),
'postgres', jsonb_build_object(
'version', current_setting('server_version'),
'version_num', current_setting('server_version_num')::integer,
'database_name', current_database()
),
'capabilities', jsonb_build_object(
'pg_stat_statements', false,
'stats_reset_known', (SELECT stats_reset IS NOT NULL FROM database_stats)
),
'database', jsonb_build_object(
'database_bytes', (SELECT database_bytes FROM database_stats),
'stats_reset', (SELECT stats_reset FROM database_stats)
),
'relations', COALESCE((SELECT jsonb_agg(to_jsonb(relation_stats) ORDER BY total_bytes DESC) FROM relation_stats), '[]'::jsonb),
'indexes', COALESCE((SELECT jsonb_agg(to_jsonb(index_stats) ORDER BY index_bytes DESC) FROM index_stats), '[]'::jsonb),
'connections', (SELECT to_jsonb(connection_stats) FROM connection_stats),
'query_stats', '[]'::jsonb
) AS databasemeter_health_check;What the script reads—and deliberately excludes
Included
- PostgreSQL version, database name and size
- Bounded relation and index statistics
- Aggregate connection states
- Optional anonymized query counters
Excluded
- Application table rows and arbitrary column values
- Passwords, connection strings, hostnames and client addresses
- SQL/query text and session query contents
- Changes, resets, plans and automatic fixes
Step 2
Choose a database or provide a result
Signed-in users can run a live check from an existing connection. Otherwise, copy the JSON value from the result cell or use a one-row JSON export. JSON and text files up to 512 KiB are read locally.
Definitions and sources
Provider and PostgreSQL statements last reviewed August 28, 2026. Pricing consoles and invoices remain authoritative.
Related database resources
PostgreSQL database size guide
Use built-in PostgreSQL functions to inspect database and relation sizes.
Open resourcePostgreSQL index size guide
Measure table and index footprint without reading application rows.
Open resourceDatabase growth calculator
Measure growth pace and a transparent threshold projection.
Open resource