ignore_checksum_failure is not a configuration parameter so much as a crowbar in a glass case. It defaults to off, it does not appear in postgresql.conf.sample at all (the sample file politely declines to advertise it), and the documentation files it under Developer Options, next to the other tools you hope never to hold. The context is superuser, which means a superuser (or a role that has been granted SET on it, which no role should be) can flip it in a live session with SET; no reload, no restart. That is exactly the granularity its one legitimate use requires. It arrived in PostgreSQL 9.3 alongside data checksums themselves: a feature that verifies, and a lever to un-verify, born together.

Here is what it un-verifies. When data_checksums are enabled (and since PostgreSQL 18 flipped the initdb default, on new clusters they are), every page read from disk into shared buffers is checksummed on the way in. A mismatch means the page changed while PostgreSQL wasn’t looking: bit rot, a failing device, a storage layer that lied about a write. The server logs page verification failed, calculated checksum 27665 but expected 21894 and your query dies with ERROR: invalid page in block 7 of relation "base/16384/16523". With ignore_checksum_failure = on, the error becomes a warning and the page is admitted anyway. The documentation, in a rare moment of open alarm, notes this may “cause crashes, propagate or hide corruption, or other serious problems,” and the documentation is right.

There is one gate even the crowbar won’t open: the page header must still pass basic sanity checks (pd_lower, pd_upper, and pd_special in bounds and properly ordered). A page whose header is garbage errors out regardless. That case belongs to zero_damaged_pages, this parameter’s more destructive sibling.

The warning undersells two consequences. First, the corrupt page is now in shared buffers, and every other backend that touches it reads it from cache with no verification and no warning; your session-scoped SET has cluster-wide effects. Second, if anything dirties that page, the next write computes a fresh checksum over the corrupted contents. The page is now “valid.” The corruption remains; the evidence is gone. Checksums verify a page at exactly one moment, the read from disk, and this parameter spends that moment.

The afternoon it exists for

When checksum failures appear, the correct response is almost never this parameter. Checksums detect corruption; backups and replicas fix it. Restore, or fail over, and then go have a hard conversation with your storage.

The parameter exists for the day there is no good backup and no clean replica. Then: work on a file-level copy of the cluster if you possibly can, SET ignore_checksum_failure = on in a single session, and COPY out everything readable. Expect the rows on the bad pages to be missing or to be lies; the rest of the table generally comes back intact. I have run this salvage in anger more than once, and the rows on the corrupt pages are the ransom you pay. RESET it the moment you are done. The accounting stays honest throughout: pg_stat_database.checksum_failures and checksum_last_failure tick even for ignored failures, and an offline pg_checksums --check will tell you the full extent of the damage.

One PostgreSQL 18 note. The exact message traffic changed with asynchronous I/O: your session sees WARNING: ignoring checksum failure in block 7 of relation ..., while the per-page detail lands in the server log, possibly attributed to an I/O worker process, because the read may complete somewhere other than your backend. The parameter’s value is captured from your session when the read is issued, so a session-level SET still does exactly what you mean.

So: off, everywhere, always, until the afternoon it isn’t. Set it in one session, take what the crowbar gives you, and put it back behind the glass.