Symptoms
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
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 = 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.
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 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.
Related & next steps
Thanks — noted. This helps keep the database accurate.