SQLSTATE XX001 WARNING Class XX: XX — Internal Error

data_corrupted PostgreSQL WARNING: Page Verification Failed, Checksum Mismatch

A streaming standby logs WARNING: page verification failed, calculated checksum X but expected Y for a specific relation. This means a data page on the standby does not match its stored checksum — eit

PG 12,13,14,15,16,17 Official docs
Last reviewed May 2026 Grounded in source
Production impact High Competency WAL & Recovery Career Own backup and recovery strategy Frequency Common

Symptoms

Conditions:

  • Standby log: WARNING: page verification failed, calculated checksum X but expected Y
  • pg_checksums was 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

Environment

Difficulty: Advanced  |  PostgreSQL versions: 12, 13, 14, 15, 16, 17

Root Cause

  • A checksum mismatch on the standby does not necessarily mean the primary is corrupt — the standby's disk may have failed.
  • zero_damaged_pages = on allows 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 --enable while stopped, existing pages have checksums written at enable time — subsequent corruption is detected.
  • A single corrupt page in an index: REINDEX the 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.

Investigation

-- 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

1 more diagnostic query

Identify the exact root cause. Find the connection leak, the bloated table, the lock holder.

Fix Now

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.

Keep going

Related & next steps

Concepts on this page

Was this helpful?