Verify PostgreSQL Data Checksums Safely with pg_checksums
You will check, enable or disable data checksums for a PostgreSQL cluster while keeping the offline boundary clear. This guide targets the locally installed PostgreSQL 16.15 tool on Ubuntu, and takes roughly 10 minutes for a small cluster, plus the scan time.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
You need the cluster data directory, access to the account that owns it, and a maintenance window. The PostgreSQL server must have been shut down cleanly before you run pg_checksums. The executable is commonly under /usr/lib/postgresql/16/bin/pg_checksums; use the path supplied by your package if yours differs.
These operations work on the whole cluster, not one database or table. Checking scans every file. Enabling rewrites relation-file blocks in place, so allow time and disk I/O. Do not start PostgreSQL, or any other program that writes to the data directory, until an enable or disable operation has finished.
Checkpoint
Have the exact data directory ready, and confirm that the service is stopped. Replace /var/lib/postgresql/16/main below with your real path.
PGDATA=/var/lib/postgresql/16/main
PGCHECKSUMS=/usr/lib/postgresql/16/bin/pg_checksums
$PGCHECKSUMS --version
test -f "$PGDATA/PG_VERSION" && echo "cluster directory found"
sudo systemctl is-active postgresql
Expected version output on this machine is:
pg_checksums (PostgreSQL) 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)
The final command should report inactive before you proceed. If it reports active, stop the correct PostgreSQL instance through your normal service-management procedure. Stopping a production database is service-disrupting, so do not guess the service name or data directory.
Check the current checksum state
Use SQL while the server is running to read the cluster-wide setting. This is a read-only check and does not replace the offline scan.
SHOW data_checksums;
A result of on means checksums are configured for the cluster. A result of off means they are not. Record the result before making a change so you can recognise the intended end state.
After a clean shutdown, run the default check explicitly with --check and show progress:
sudo -u postgres "$PGCHECKSUMS" --check --progress --pgdata="$PGDATA"
printf 'exit status: %s\n' "$?"
A successful scan exits with status 0 and reports no checksum failures. A non-zero status means the scan found at least one checksum failure, or that the operation could not run. Keep the complete output and investigate before treating the cluster as healthy. The command checks the whole cluster unless you deliberately use the filenode filter described below.
Enable checksums
Only do this after confirming that the cluster is stopped and that checksums are currently off. Enabling changes relation files in place and can take a long time on a large cluster.
sudo -u postgres "$PGCHECKSUMS" --enable --progress --pgdata="$PGDATA"
enable_status=$?
printf 'enable exit status: %s\n' "$enable_status"
A zero status means the operation completed. A non-zero status means it failed; do not start the server just because the command returned. If the process is aborted or killed, the checksum configuration remains unchanged and the same operation can be run again.
Once the command succeeds, start PostgreSQL through your usual service procedure, then verify the setting:
SHOW data_checksums;
The expected result is on. Stop the server again before any later offline check or change.
Disable checksums only with a rollback plan
Disabling is also a cluster-wide offline change. It updates pg_control rather than rewriting every relation block, but it removes checksum protection for future reads. Treat this as a deliberate compatibility or recovery decision, not as a routine troubleshooting switch.
sudo -u postgres "$PGCHECKSUMS" --disable --progress --pgdata="$PGDATA"
After a zero exit status, start the server and confirm SHOW data_checksums; returns off. To undo this change, stop the cluster cleanly and run the enable command again. That re-enables checksums by rewriting the required relation-file blocks.
Useful narrow checks and safe defaults
--filenode=FILENODE limits validation to the relation with the supplied filenode. Use it only when you already have a verified filenode from PostgreSQL diagnostics. It is not a substitute for the full-cluster check.
sudo -u postgres "$PGCHECKSUMS" --check --filenode=12345 --pgdata="$PGDATA"
Do not add --no-sync to a production enable or disable. It returns before changes are safely written, so a later operating-system crash can corrupt the data directory. It has no effect with --check; the normal synchronous behaviour is the safer default.
--verbose lists checked files and --progress reports progress. These options change output, not the checksum decision. If you prefer the environment, PGDATA supplies the directory when no --pgdata argument is given, but an explicit path makes a maintenance command easier to audit.
Replication warning
In a replication setup, keep the checksum setting consistent across every cluster when using tools that copy relation-file blocks directly, such as pg_rewind. An inconsistent switch can produce pages with incorrect checksums. Stop all clusters before switching them consistently; rebuilding standbys from the changed primary is the safest clean reset when your recovery plan allows it.
Done means
- The server was shut down cleanly for every offline command.
- The full
--checkscan returned status 0, or any reported failure is being investigated. SHOW data_checksums;matches the intended cluster state after a controlled restart.- No process writes to the data directory during enable or disable.
- Replication peers, backups and recovery procedures reflect the same checksum decision.