Tutorial · wordpress · Published 2026-08-15 · 4 min read
Restore WordPress from a backup
Restore WordPress from a backup: restore files before the SQL, fix wp-config credentials, then repair siteurl and home if the domain changed.
The restore order that never breaks
A WordPress restore is two independent parts that must come back in sequence: files, then database. Restoring the SQL over an old or missing file tree produces a mix of old and new that is the source of most "restored but broken" stories. The safe order is fixed:
- Restore the files (the whole site,
wp-config.phpandwp-contentand core). - Restore the database (the SQL dump, into a schema WordPress connects to).
- Point
wp-config.phpat the restored database. - Test, then correct
siteurlandhomeif the domain changed.
Step 1: Prepare the landing zone
Create the target directory and a known PHP version. Confirm the database server is reachable and the target schema exists (or create it via phpMyAdmin):
CREATE DATABASE wordpress_restored;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'strongpass';
GRANT ALL PRIVILEGES ON wordpress_restored.* TO 'wpuser'@'localhost';
Step 2: Restore the files first
Upload the file tree so the web server serves the same code as the dump expects:
tar -xzf site-files.tar.gz -C /var/www/example.com
chown -R www-data:www-data /var/www/example.com
find /var/www/example.com -type d -exec chmod 755 {} \;
find /var/www/example.com -type f -exec chmod 644 {} \;
A common trap: the archive contains the site inside a folder of its own (example.com/...), so check the top level and move the contents up one level in that case.
Step 3: Import the database
Import into the empty schema, not into a live one, so the dump's prefix and rows land cleanly:
mysql -u wpuser -p wp_rest < wp-dump.sql
Also confirm the dump is a full dump (contains CREATE TABLE entries for wp_options and wp_users) and not a partial plugin export; a missing wp_users table produces "error establishing a database connection" even with correct credentials.
Step 4: Point wp-config at the restored database
Edit wp-config.php with the new values you created in step 1:
define('DB_NAME', 'wp_rest');
define('DB_USER', 'wpuser');
define('DB_PASSWORD', 'strongpass');
define('DB_HOST', 'localhost');
If the database host differs from the web host, set the host explicitly (the database connection error article covers the host-string traps).
Step 5: Test the site
Load the front end and wp-login.php in a private window. Two very common test failures and their fixes:
| Symptom | Meaning | Fix |
|---|---|---|
| "Error establishing a database connection" | Credentials, host, or prefix mismatch | Reread step 4 |
| Admin loads but URLs point at the old domain | siteurl / home in wp_options carry the old address | Step 6 |
| White or blank page | PHP version or mixed files | Compare PHP version and re-extract files |
Step 6: Fix siteurl and home if the domain changed
If you restore to a new domain or IP, the two URL settings still point at the old address, which breaks links, uploads, and the login redirect (the login-loop article covers that). Update them with WP-CLI, which bypasses the boot:
wp option update siteurl 'https://new-domain.example'
wp option update home 'https://new-domain.example'
For content-level URLs (photos in post bodies, image src stored full), run a search-replace, never manual find in the dump:
wp search-replace 'https://old.example' 'https://new.example' --all-tables --precise --skip-columns=guid
--precise avoids touching serialized data lengths, which naive sed breaks. --skip-columns=guid leaves the guid column alone; a post GUID is meant to be permanent and rewriting it can confuse feed readers and imports.
Step 7: Clear caches after the restore
Restores leave stale copies behind at several layers, and the stale copies can replay old URLs or old markup right after you finish:
wp cache flush
Then clear the page cache, object cache, and the CDN edge in the host panel or plugin dashboard, and purge any reverse-proxy cache the web layer keeps. A cached home page from the pre-restore state sticks longer than the restore itself, so the cache clear is part of the restore, not an optional extra.
Step 8: Finish and verify
- Log out and back in to confirm sessions issue.
- Check Site Health to confirm no whitelisted file changed and the plugins you expect are active.
- Move the old backup location out of the web root; a
.sqlfile reachable from the web is a leak.
The restore order in one runnable mental model: files before SQL, SQL before config, config before siteurl, caches purged last.