A backup you have never restored is not a backup. It is a file you are hoping about. The only way to know your WordPress site can be recovered is to recover it — into a throwaway environment, on a normal Tuesday, with a stopwatch running and a checklist in hand.
The test itself is short. Take the most recent backup, restore it somewhere that is not production, and then check five things: the site loads, you can log in, the content is current, the media files are present, and the money paths work. Write down how long it took. That number is your real recovery time, and for most sites it is three to ten times longer than the owner assumed.
What follows is the procedure we use, the failure modes it catches, and an honest look at what your backup plugin does and does not cover.
What a restore test actually proves
Backup software is good at making files. The failures almost never happen at that stage. They happen at restore, and they are usually failures of scope rather than corruption — something that mattered was never inside the archive in the first place.
A completed restore test answers four questions that a green checkmark in a plugin dashboard does not:
- Is the archive complete? Database and files, including the whole uploads directory, not just the most recent year.
- Can it be read back? A SQL dump that was truncated mid-write imports with errors that are easy to miss if nobody is watching the output.
- How long does it take? Measured end to end, including download time from remote storage, which on a 4 GB archive over a slow link is most of the window.
- What is missing afterwards? Licence keys, cron schedules, server-level configuration, DNS, mail routing. These live outside WordPress and outside the backup.
That last one is where most recoveries go sideways. The site comes back; the order confirmation emails do not.
The four ways WordPress backups fail at restore time
| Failure | What you see | Why it happened | Caught by |
|---|---|---|---|
| Incomplete file set | Site loads, images are broken, old posts show missing media | The uploads folder was excluded by a size cap or a stale exclusion rule, or the backup job timed out partway through | Comparing file counts and total size in wp-content/uploads between source and restore |
| Truncated or failing SQL import | White screen, “Error establishing a database connection”, or missing tables | The dump hit a packet or timeout limit, or a single large table (often wp_options or wp_postmeta) exceeded what the import could swallow in one statement | Importing with errors visible rather than through a UI that swallows them |
| URL and serialized data damage | Site loads but layouts collapse, widgets empty, page-builder content blank | A find-and-replace was run with a plain SQL query instead of a serialization-aware tool, breaking the length prefixes inside serialized PHP strings | Loading a page-builder page and a widget area on the restored copy |
| Everything outside WordPress | Site works, but payments, email, redirects or scheduled jobs do not | Payment gateway keys, SMTP credentials, server-level redirects, cron entries and firewall rules were never in the archive | Walking a checkout and triggering one transactional email on the restored copy |
The third row is worth dwelling on. WordPress stores a lot of configuration as serialized PHP, where each string carries its own byte length. Change http://old.example to https://new.example with a blunt SQL REPLACE() and the stored lengths no longer match the strings, so PHP refuses to unserialize them and the option comes back empty. WP-CLI’s search-replace exists specifically to avoid this: the documentation states that it “intelligently handles PHP serialized data, and does not change primary key values.” Use it, or use your migration plugin’s own replace routine. Never use raw SQL.
How to run a restore test in under an hour
You need somewhere that is not production. A host staging environment, a second cheap hosting account, or a local environment all work. What matters is that it is isolated — no shared database, no shared uploads directory, and search engines blocked.
Step 1 — Take the backup you would actually use
Not a fresh one made for the test. Pull the most recent scheduled backup from wherever it normally lands, including the download step, because download time is part of recovery time.
Step 2 — Restore into the isolated environment
If you are restoring by hand rather than through a plugin, WP-CLI is the shortest path. These commands run against the restore environment:
# 1. Put the files in place, then import the database
wp db import backup.sql
# 2. Check the import did not silently hit a size limit
wp db query "SHOW VARIABLES LIKE 'max_allowed_packet';"
# 3. Rewrite URLs — dry run first, always
wp search-replace 'https://example.com' 'https://staging.example.com' \
--all-tables --dry-run --report-changed-only
# 4. Then for real
wp search-replace 'https://example.com' 'https://staging.example.com' \
--all-tables --precise
# 5. Confirm the site is up and nothing fatal is loading
wp option get siteurl
wp plugin list --status=active --format=count
wp cron event list --format=countwp db import runs the SQL through the MySQL client using the credentials in wp-config.php; it does not create the database for you, so the empty database has to exist first. If the import throws packet-size errors, raise max_allowed_packet on the restore server and run it again — do not assume the partial import is fine because the home page rendered.
The --precise flag on step 4 forces PHP processing on every column instead of the faster SQL path. It is slower, and on a large database noticeably so, but it is the right default for a test where you are trying to prove correctness rather than finish quickly.
Step 3 — Walk the checklist, with a timer
Start the clock when you begin the download and stop it when the checklist below is fully green. That elapsed time is the number to report, not the plugin’s “restore complete” toast.
The pass/fail checklist
| Check | Pass condition | Fails most often because |
|---|---|---|
| Home page and three interior pages load | HTTP 200, no PHP notices, layout intact | Page-builder content stored as serialized data was damaged in the URL rewrite |
| Admin login | You can log in as an administrator | A security plugin’s IP allowlist or 2FA table came across and now locks you out of an environment it does not recognise |
| Content recency | The newest post, product or order matches what production had at backup time | The backup ran before the day’s work, so the real RPO is worse than the schedule suggests |
| Media integrity | File count and directory size in wp-content/uploads within a rounding error of production | Size caps or exclusions silently skipped large or old media |
| Forms and transactional email | One test submission sends and arrives | SMTP credentials were in a plugin setting that did not survive, or in server config that was never backed up |
| Checkout (WooCommerce) | A test-mode order completes and writes to the database | Gateway keys are environment-bound and were never part of the archive |
| Scheduled tasks | wp cron event list shows the expected jobs | A real server cron entry was driving WP-Cron and lives outside WordPress |
Anything that fails here is a gap in the backup policy, not a bug in the plugin. Write the missing item into a recovery runbook — a short document listing the credentials, DNS records and server settings a rebuild needs — and store it somewhere that is not the site.
[Reviewer note: this section is the natural place for a real restore-time figure from a Dealinweb client — e.g. the measured gap between a client’s assumed recovery time and the stopwatch result on the first drill. Prose reads complete without it.]
If you have never run this drill and would rather not discover the gaps during an actual outage, we can run a restore test against your current backups and give you the checklist filled in, including the measured recovery time.
What your backup tool actually covers
Plugin marketing tends to blur backup frequency with recovery guarantees. These are the current published terms for three common choices, plus the host snapshot option that many sites rely on without realising it.
| Option | Frequency | Retention | Restore testing | Notable limit |
|---|---|---|---|---|
| UpdraftPlus (free) | Manual, or scheduled every 2/4/8/12 hours, daily, weekly, fortnightly or monthly | Whatever your remote storage keeps | None built in — you restore somewhere else yourself | Incremental backups, pre-update backups, WP-CLI control and multisite are Premium-only |
| BlogVault | Daily (Personal), twice daily (Business), hourly (WooCommerce) | 30 / 90 / 365 days by plan | Test restore to a separate environment, on their infrastructure | Staging retention differs by plan: 1 day, 30 days, 6 months |
| Jetpack VaultPress Backup | Real-time | 30-day activity log on paid plans; longer archives on higher tiers | One-click restore; no dedicated test-restore sandbox | Storage is capped and metered — 10 GB at the entry tier |
| Host snapshots | Usually nightly | Typically a rolling window of days | Only if the host offers staging | Lives on the same provider as the site; if the account is suspended or compromised, so is the backup |
Prices and plan contents change, so check the vendor page before you commit. The structural point does not change: real-time capture and one-click restore are different promises from verified recoverability, and only the third one is what you need at 2 a.m.
The host-snapshot row deserves a blunt reading. Snapshots held by your hosting provider protect you from your own mistakes. They do not protect you from a billing dispute, an account suspension, or a compromise that reaches the control panel. That is why the old 3-2-1 rule still holds: three copies, on two kinds of storage, with one of them somewhere else entirely.
RPO and RTO, without the jargon
Two numbers decide what your backup schedule should be, and both are business decisions rather than technical ones.
RPO — how much data you can afford to lose. It equals your backup interval. Nightly backups mean that a failure at 5 p.m. loses a day of orders, comments and form submissions. For a brochure site that is nothing. For a store taking thirty orders a day it is thirty customers who paid and have no record of it.
RTO — how long you can afford to be down. This is the measured number from your drill, not an estimate. A 4 GB archive that must be downloaded from cloud storage over a 50 Mbit link takes roughly eleven minutes just to transfer, before anything is imported. Add database import, URL rewriting, DNS or cache clearing, and verification, and an hour is a realistic floor for a manual restore of a mid-sized site.
If the measured RTO is longer than the business can tolerate, the fix is usually not a different plugin. It is keeping a warm standby, or shrinking the archive by moving large media to object storage, or paying for a service that restores on its own infrastructure rather than yours.
How often to test
A full drill once a quarter is enough for most sites, with a lighter check each month. Also test after any event that changes the shape of the site: a host migration, a PHP version change, a new backup plugin, a jump in database size, or a move to a new payment gateway. Those are precisely the changes that quietly invalidate a backup routine that worked last year.
Make the result a one-line log entry — date, backup used, measured recovery time, what failed. Four entries a year is a complete record, and it is the fastest way to see your recovery time drifting upward as the site grows.
Restore testing belongs alongside the other recurring jobs in a WordPress maintenance routine, next to the update process — because the most common reason anyone needs a restore in the first place is an update that broke something. The second most common is a compromise, and a verified backup is what turns the first hour after a hack from a rebuild into a rollback. If you are weighing what ongoing care should cover, what a maintenance plan should actually buy you sets out the baseline.
Start with one drill
Pick your most recent scheduled backup, restore it into staging this week, and time it. Whatever that number is, it is the truth about your recovery — and if the result is unpleasant, it is far better to learn it now than during an outage.
If you would rather hand the drill to someone who has done it before, get in touch. We will restore your current backup into an isolated environment, work the checklist above, and send you the measured recovery time along with a list of everything that did not come back.
