Blog

A Database Backup Is Only Half a Website

A WordPress database backup only covers half your site. See exactly what it misses, the mysqldump flags that stop a torn export, and how to restore one safely.

WordPress database backup covering posts, users and settings alongside a website files backup of themes, plugins, media and config files, both sent to offsite cloud storage

Most people who search for a WordPress database backup already assume the database is the site. It isn't. Rebuild a site from a database-only export as a deliberate test rather than waiting for a real emergency to find out, and the restored site comes back broken in a way the owner didn't expect — reliably.

The database holds your posts, pages, comments, and settings. But your uploaded images, your active theme's code, your custom plugins, your .htaccess rewrite rules, and the secret keys in wp-config.php all live outside it, on disk. Grab only the database, and you're backing up roughly half the website.

This guide walks through what the database does and doesn't hold. It covers what breaks when you restore from a database-only dump. It shows how to take a dump that won't quietly truncate itself mid-export. And it covers when a database-only backup is genuinely the right tool for the job, rather than a trap.

What Actually Lives in the Database — and What Doesn't

A WordPress database (almost always MySQL or MariaDB) stores roughly a dozen core tables: wp_posts, wp_postmeta, wp_options, wp_users, wp_usermeta, wp_terms, and a handful more depending on which plugins add their own tables. That's where your post content, page content, comments, menu structure, widget settings, and most plugin configuration live. It is, genuinely, the most frequently changing part of a WordPress site — which is exactly why so many people reach for a database backup first.

That table also holds something that isn't really "content" at all: every saved revision of every post and page, stacking up indefinitely unless a limit is set. See why WordPress revisions are not a backup for how that bloat affects the size of the dump you're about to take, and why trimming it is good database hygiene but still no substitute for the backup itself.

Here's what the database does not contain, according to the WordPress.org database backup documentation: the wp-content/uploads/ directory (every image, PDF, and video you've ever uploaded), the active theme's PHP and CSS files in wp-content/themes/, every installed plugin's code in wp-content/plugins/, any mu-plugins/ you or a host added, the site's .htaccess file (or nginx config) that controls permalinks and redirects, and wp-config.php itself. That last file holds your database credentials and your unique authentication salts.

We built a quick reference table from the WordPress.org Codex file-structure guide so you can check your own backup set against it in under a minute:

Lives in the databaseLives on disk (files)
Posts, pages, commentsUploaded media (wp-content/uploads/)
Site settings (wp_options)Theme code (wp-content/themes/)
User accounts and rolesPlugin code (wp-content/plugins/)
Menu structure, widgetsSite-level mu-plugins
Most plugin configuration.htaccess / server rewrite rules
Comment metadata, taxonomieswp-config.php (credentials + salts)

The Symptom → Missing Artifact Table

This is the section most "how to back up WordPress database" guides skip, and it's the part that actually explains what you're looking at when a database-only restore goes wrong. These symptoms trace back to the same handful of missing files every time.

Symptom after restoreWhat's actually missing
Every image on the site shows a broken-image iconwp-content/uploads/ — the database only stored the URL path to each file, not the file itself
White screen or 500 error right after activationThe active theme or a plugin's PHP files — the database has a row saying "Twenty Twenty-Four is active," but not the theme's code
All your custom permalinks 404, pretty URLs stop working.htaccess — WordPress can regenerate it from Settings > Permalinks, but only after you resave it manually
A plugin's custom fields or settings panel comes back emptyAny plugin table it created itself plus its uploaded assets — if the plugin's code wasn't reinstalled first, its database rows have nothing to attach to
Login works but every session gets logged out instantlyFresh authentication salts in a new wp-config.php invalidate old session cookies — expected, but confusing if you weren't told
Site loads but every link points to the old domainwp_options rows (siteurl, home) weren't updated for the new host — a database-only migration problem, not a missing-file one

Notice that the last two rows are database problems, not file problems — which is the other side of this coin. A database-only backup restored onto the same server, same domain, same file structure, can genuinely work. The moment any of those three things change, you need the files too.

mysqldump vs. phpMyAdmin Export: Size Limits, Timeouts, and the Truncated.sql Nobody Notices

If you're exporting manually rather than through a backup plugin, you have two realistic options, and they fail differently.

phpMyAdmin's export tab is the most common path because every shared host exposes it. The problem: it runs inside PHP's own request lifecycle. That means it's bound by max_execution_time and upload_max_filesize. On a typical shared host those caps sit around 30 to 60 seconds and 2–8 MB respectively. According to the database backup guidance above, a database over roughly 50 MB routinely times out or produces a truncated file. That size is not unusual once you've got a few years of comments and revisions. The export file looks fine in a file browser. It opens fine in a text editor. It only fails when you try to restore it, and MySQL throws a syntax error on the truncated last line. Some site owners install a dedicated export plugin instead — the WP Database Backup plugin on WordPress.org is one example — specifically to sidestep this PHP timeout problem.

mysqldump, run from the command line or SSH, isn't bound by PHP's limits at all. It's a native MySQL client talking directly to the server process. A 2 GB database dumps the same way a 20 MB one does — it just takes longer. The command most guides give you is incomplete, though:

mysqldump -u username -p database_name > backup.sql

That works for a quiet site. For anything receiving live traffic — checkout flows, comment submissions, logged-in editors — you want one more flag.

Consistency: --single-transaction on InnoDB, and Why a Dump Taken Mid-Checkout Can Tear

Most WordPress tables run on the InnoDB storage engine, which supports transactions. Without --single-transaction, mysqldump reads your tables one at a time, in sequence, while the site keeps writing to all of them. Say an order comes in halfway through the dump. wp_posts has already been read, but the related wp_postmeta row for that order hasn't landed yet. Your backup now captures a database that never actually existed — half of a transaction, with the other half missing. This isn't a rare edge case on a store that takes orders continuously — without the flag, dumps taken during active writes can regularly produce an orphaned postmeta row. With it, the dump is a consistent snapshot and the problem goes away.

mysqldump -u username -p --single-transaction --quick database_name > backup.sql

--single-transaction takes a consistent snapshot at the instant the dump starts — every table reads as it looked at that exact moment, not as it evolves during the (potentially multi-minute) export. --quick streams rows instead of buffering the whole result set in memory first, which matters once a table passes a few hundred thousand rows.

Restoring a.sql File: DROP vs. Merge, Collation Match, and the wp_options Gotcha

Restoring is where most of the remaining failures happen, and they're almost always one of three things.

DROP vs. merge. A straight mysql -u user -p database_name < backup.sql assumes the target database is either empty or you want the dump's tables to fully overwrite anything with the same name — it does not merge rows. If you're restoring onto a database that already has content you want to keep, you'll end up with duplicate or conflicting primary keys unless you first drop the existing tables or restore into a clean schema.

Collation match. Say the source site was created years ago under utf8_general_ci. Now you're restoring into a fresher MySQL instance that defaults to utf8mb4_unicode_520_ci. Certain joins and comparisons can silently behave differently. The most visible sign is mangled emoji or multi-byte characters in older posts. Match the collation on the target database to what the dump file specifies, before importing.

The wp_options gotcha. Two rows in wp_options — siteurl and home — hard-code the domain the backup was taken from. Restore that dump onto a staging subdomain or a new production domain without updating those two rows, and every internal link, every image src, and the admin login redirect will all point back at the original domain. The same applies to serialized data inside wp_posts and wp_postmeta, which needs its own search-and-replace pass.

wp-config.php and Salts: What You Must Keep, What You Must Never Publish

The wp-config.php file is not stored in the database, and it's not optional. It holds your database name, username, password, and host — the credentials the site uses to even reach the database you just backed up. It also holds eight unique authentication salts (AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY, and their _SALT pairs) that encrypt session cookies. Lose this file with no copy anywhere, and a database-only backup is nearly useless on its own. You'd be rebuilding the connection details from scratch. Every logged-in session invalidates the moment the salts change.

Keep a secured copy of wp-config.php alongside your database dumps, in the same backup set. Never store it in a public repository or an unprotected cloud folder — the credentials and salts inside it are exactly what an attacker would want. If you regenerate salts for a fresh install, expect every currently logged-in user, including you, to be signed out immediately. That's expected behavior, not a bug.

When a Database-Only Backup Genuinely Is Enough

None of this means you should abandon database exports. They're fast, they're small, and for one specific job they're exactly the right tool: refreshing a staging copy of a site you already have the files for. Say your staging environment already has the current theme and plugin code installed, and you just want it to reflect this morning's content changes. A database-only sync is the quickest way to get there, since the files already match and there's nothing on disk to touch. That's the workflow our guide on backing up WordPress without plugins over SSH covers for the no-plugin case specifically.

The rule of thumb: if the destination's files already match the source, a database-only backup is sufficient. If they don't — a new server, a new host, a disaster recovery scenario, or you genuinely don't know — you need the files too, every time.

What a Complete Backup Actually Covers

A full WordPress backup, as opposed to a database-only one, needs to capture four things together, kept as one recoverable set: the database, the wp-content/uploads/ directory, the active theme and all installed plugins, and a secured copy of wp-config.php plus any server-level redirect rules. BackupYourSite's own automated backups package all four into a single scheduled job, including on hosts like WP Engine where the SSH Gateway handles direct access. Handling any one of those four pieces separately, on its own schedule, is exactly how a restore ends up with one of the missing-artifact symptoms in the table earlier in this piece.

Our full feature set page walks through the scheduling, storage, and one-click restore pieces if you want to see how that's structured end to end, rather than piecing it together by hand. Our how it works page covers the mechanics in more depth. And if "what even counts as a backup" is still the open question, start with what is a WordPress backup, exactly.

How Often Should the Database Actually Be Dumped?

This depends entirely on how fast your content changes, not on a fixed industry number. A static brochure site with five pages and no comments can run weekly and lose nothing meaningful between dumps. A WooCommerce store processing orders every few minutes cannot. A reasonable baseline for an active store is every six hours, tightened to hourly during sale periods when order volume spikes. A blog with daily posts and an active comment section sits comfortably on a once-a-day schedule.

The deeper question isn't "how often" — it's "how much am I willing to lose." Six hours between dumps means a worst-case loss window of six hours of orders, comments, and edits. Map that window against what a lost morning of sales actually costs your business, in rupees or dollars. The right frequency becomes obvious fairly quickly once you do that math. Automated scheduling removes the risk of simply forgetting — in practice, forgetting is the single most common cause of an unusable backup set. Not corruption, not a bad dump, just nobody having run one in the weeks before the site broke.

Retention matters as much as frequency. Keeping only the most recent dump means a corrupted or malicious change made two days ago gets faithfully "backed up" right over the good copy. A rolling window of at least 7 to 14 days gives you somewhere to go back to before the bad change, not just before the crash.

Frequently Asked Questions

Is a WordPress database backup enough on its own?

Only if you're restoring onto the exact same files — same theme, same plugins, same server config — and just need the content to come back. For a new host, a new domain, or disaster recovery, you also need wp-content/uploads/, your theme and plugin code, and wp-config.php.

How do I back up my WordPress database without a plugin?

Run mysqldump over SSH with the --single-transaction and --quick flags, which keeps the export consistent even while the site is actively being written to. See our no-plugin backup guide for the full SSH walkthrough.

Why does my site show broken images after a database restore?

Because the database only ever stored the path to each uploaded file, never the file's binary data. The actual image files live in wp-content/uploads/ on disk, and a database-only restore doesn't touch that directory at all.

Can I export a WordPress database using phpMyAdmin instead of the command line?

Yes, for small sites. But phpMyAdmin runs inside PHP's own execution limits, so databases above roughly 50 MB routinely hit a timeout or file-size cap and produce a truncated .sql file that looks complete but fails on restore.

What is --single-transaction in mysqldump and do I need it?

It takes a consistent snapshot of InnoDB tables at the instant the dump starts, instead of reading tables one by one while the live site keeps writing to them. You need it on any site that gets traffic or logged-in activity during the backup window — without it, a dump taken during active writes can come out torn, with some tables reflecting a later moment than others.

Why do all my links point to the old domain after I restore my database?

The siteurl and home rows in wp_options hard-code the domain the backup was taken from, and serialized URLs are also embedded throughout wp_posts and wp_postmeta. Moving to a new domain or host needs a search-and-replace pass across the database, not just a straight restore.

Do I need to back up wp-config.php separately from the database?

Yes. It's a file on disk, not a database table, and it holds your database connection details plus the authentication salts WordPress uses to validate login sessions. Keep it in the same secured backup set as your database dump — never in a public location.

When is a database-only backup actually fine to rely on?

When you're refreshing a staging environment that already has the current theme and plugin files installed, and you only need this morning's content changes carried over. The destination's files already match the source, so there's nothing else to restore.