A Backup You Have Never Restored Is a Rumour

I once sat in a darkened server room at 2 AM, listening to the hum of cooling fans, staring at a terminal window that refused to acknowledge a single line of my recovery script. We had the “perfect” automated pipeline, the high-availability clusters, and the expensive enterprise storage, but when the corruption hit, we realized we didn’t have database backups you have actually tested; we had a collection of expensive, unreadable files. There is a specific, cold hollow in your stomach when you realize your entire disaster recovery strategy is nothing more than a hopeful assumption written in a configuration file.

I’m not here to sell you on more expensive tooling or show you a sanitized “happy path” tutorial that assumes everything goes right. I want to talk about the messy reality of the restore process—the permission errors, the checksum mismatches, and the inevitable way a 500GB dump behaves differently than a 5MB test case. I’m going to share the specific, grueling steps I use to validate my data, focusing on the edge cases that actually break your systems so you aren’t caught off guard when the real crisis arrives.

Table of Contents

Where Database Integrity Verification Went to Die

Where Database Integrity Verification Went to Die.

In my experience, database integrity verification usually dies in the gap between “the script finished” and “the data is actually usable.” Most teams treat a successful exit code from a backup job as a victory lap. They see a green checkmark in the monitoring dashboard and assume the job is done. But a successful write to a storage bucket tells you nothing about the internal consistency of the pages you just saved. I’ve spent weeks untangling corrupted WAL files that looked perfectly fine to the automation, only to realize the underlying block was unreadable.

The real death occurs when we stop treating point in time recovery validation as a requirement and start treating it as a suggestion. We fall into the trap of checking for file existence rather than actual content validity. We stop measuring our RTO and RPO benchmarks against reality and start measuring them against what we hope will happen during a crisis. When you rely on automated backup verification tools that only check for checksum mismatches, you’re missing the subtle, creeping rot of logical corruption that no simple hash can catch.

When Rto and Rpo Benchmarks Became Lies

When Rto and Rpo Benchmarks Became Lies

We treat RTO and RPO benchmarks like sacred commandments in our architecture diagrams, but in practice, they are often just optimistic fiction. I once sat through a stakeholder meeting where we confidently presented a recovery time objective of fifteen minutes. It sounded professional. It looked good on a slide. But that number didn’t account for the reality of pulling a massive WAL archive over a saturated network link or the sheer time it takes for a massive index to rebuild after the data is finally live.

The gap between a theoretical benchmark and a real-world disaster is where the panic sets in. You can run all the automated backup verification tools you want, but if they only check for file existence and not the actual usability of the data, you’re just measuring the speed at which you can fail. I’ve seen teams celebrate high restoration success rates in staging environments, only to realize during a real incident that their point in time recovery validation failed because the transaction logs were subtly corrupted three days prior. A benchmark isn’t a guarantee; it’s just a target that the universe loves to move.

Five ways to stop lying to yourself about your disaster recovery plan

  • Stop checking the “Success” flag in your cron logs. A successful exit code from a backup script only means the process finished; it doesn’t mean the resulting blob isn’t a 40GB file of null bytes because the disk ran out of space mid-stream.
  • Test the restore on different hardware. I once saw a recovery fail because the staging environment had a different CPU architecture than production, causing a specific binary extension to choke during the data re-import.
  • Automate the checksum, not just the copy. If you aren’t running a validation script that compares the source data against the restored instance, you aren’t testing a backup; you’re just hoarding expensive, useless files.
  • Factor in the “Human Latency” of your recovery. Your RTO (Recovery Time Objective) isn’t just how long the script runs; it’s how long it takes to wake up the DBA, find the encryption keys that were rotated six months ago, and realize the person who wrote the documentation left the company in 2019.
  • Practice the “Partial Failure” scenario. Most people test a full wipe and restore, but real life is usually a single corrupted table or a botched migration. If you can’t restore a specific subset of data without rolling back the entire cluster, your granularity is a liability.

The hard truths of a failed recovery

A backup is just a pile of expensive, useless bits until you’ve successfully piped it into a staging environment and verified the schema actually matches your current production state.

Stop treating RTO and RPO as theoretical math problems in a slide deck; if your recovery script takes four hours to run because of unoptimized indexing, your “five-minute” benchmark is a lie.

Automated verification must include the “unhappy path”—test what happens when the backup file is truncated, the storage bucket is read-only, or the checksums simply don’t align.

The difference between a plan and a reality

A backup is just a collection of bits until you’ve watched a restoration script hang at 98% because of a single corrupted index page while the production environment is screaming for help.

Pernille Askeland

The cost of being wrong

Understanding the cost of being wrong.

At the end of the day, a backup isn’t a file sitting in an S3 bucket; it is a successful restoration process. We have seen how integrity checks fail because we assumed the checksums were enough, and how our recovery timelines evaporate the moment we hit a network bottleneck or a corrupted WAL file. If you aren’t regularly forcing your system to fail—actually pulling the plug on a staging instance to see if your scripts hold up—then you don’t have a disaster recovery plan. You just have a false sense of security that will eventually expire at the worst possible moment.

I don’t write these posts to scare you, though I know my perspective can lean that way. I write them because I’ve spent enough years in the trenches of legacy payment systems to know that the “happy path” is a myth. The goal isn’t to build a perfect system that never breaks; the goal is to build a system where you actually know how to fix it when it inevitably does. Stop trusting the green checkmarks in your monitoring dashboard and start testing the breakage. That is the only way to sleep soundly when the real errors start rolling in.

Frequently Asked Questions

How do you actually automate the verification process without just checking if the file exists?

Checking if a file exists is just verifying you have a pile of useless bytes. To actually automate this, you need to spin up an ephemeral instance—a containerized sidecar, if you will—and run a real restore. Don’t just check the exit code; run a checksum against a known dataset or execute a specific suite of smoke tests against the schema. If your automated script can’t query a single row, your backup is a lie.

What’s the best way to test a restore on a production-sized dataset when you don't have the infrastructure to mirror it?

You don’t mirror the infrastructure; you mirror the constraints. Stop trying to spin up a full replica and start testing the recovery of a statistically significant slice. I pull a random 5% subset—ensuring it includes your most complex relational schemas and largest blobs—and restore that to a cheap, isolated instance. If your checksums pass on the subset, you’ve validated the logic. If they fail there, the full 2TB restore is just a very expensive way to confirm your disaster.

At what point does the cost of frequent, deep-integrity testing outweigh the actual risk of a silent corruption?

It’s a calculation of diminishing returns. If you’re running full checksum validations on petabytes of cold storage every week, you aren’t managing risk; you’re just burning engineering hours and IOPS. I find the sweet spot is testing the “hot” transactional data frequently, while treating the historical archives with periodic, sampled deep-scans. You stop when the cost of the test exceeds the cost of the outage—but remember, silent corruption doesn’t care about your budget.

About Pernille Askeland

I write the part the tutorial skipped: what it looks like when it breaks.

Scroll to Top