PostgreSQL WARNING: Page Verification Failed, Checksum Mismatch
! Symptoms Free
Conditions:
- Standby log:
WARNING: page verification failed, calculated checksum X but expected Y pg_checksumswas enabled on the cluster- Specific table or index is consistently causing the warning
- Primary does not show the same warning for the same table
- SMART data or filesystem errors on the standby storage
1 Environment & reproduce Free
Difficulty: Advanced | PostgreSQL versions: 12, 13, 14, 15, 16, 17
? Root cause Free
- A checksum mismatch on the standby does not necessarily mean the primary is corrupt — the standby's disk may have failed.
zero_damaged_pages = onallows PostgreSQL to return zero-filled pages instead of erroring — useful for reading around corrupt blocks to dump other data, but hides corruption.- Always verify the primary shows the same or different checksum for the same page before deciding which copy is correct.
- Checksums detect corruption but cannot fix it — the fix is restoring from backup.
- If checksums were enabled with
pg_checksums --enablewhile stopped, existing pages have checksums written at enable time — subsequent corruption is detected. - A single corrupt page in an index:
REINDEXthe index. A corrupt heap page: restore from backup is the only safe option.
Verify primary does not show the same corruption. Check standby storage health. Rebuild standby from pg_basebackup. If primary is also corrupt: restore the affected table from backup.
2 Diagnose Free
RESULT-- Check if checksums are enabled: SELECT name, setting FROM pg_settings WHERE name = 'data_checksums'; -- OR: pg_controldata $PGDATA | grep "Data page checksum version" -- 0 = disabled, 1 = enabled -- On standby: check for corrupted blocks: -- pg_filedump -i -s $PGDATA/base/oid/relfilenode | grep "checksum" -- Check for storage errors (OS): -- dmesg | grep -i "error\|EIO\|sector" | tail -20 -- smartctl -a /dev/sda | grep "Reallocated\|Uncorrectable" -- Identify which table is affected: SELECT relname, relkind, reltablespace FROM pg_class WHERE relfilenode = 12345; -- use OID from the warning message
🔒 Diagnose deeper Pro
Find every latent occurrence before it ships
The steps above clear this incident. Pro adds the executed, verified depth that stops the whole class of bug across your fleet.
- ✓Catalog & log queries that surface every at-risk object before a migration ships.
- ✓Inspect-without-running tricks (
\gdescand friends). - ✓Exactly where the log line surfaces on RDS, Azure & Cloud SQL.
- ✓Cross-version gotchas, verified on PostgreSQL 14–18.
Every Pro query on this site is executed against real PostgreSQL and verified — we never publish an untested snippet.
Already a member? Log in
3 Recovery & verify Free
Verify primary does not show the same corruption. Check standby storage health. Rebuild standby from pg_basebackup. If primary is also corrupt: restore the affected table from backup.