All posts
TroubleshootingMay 7, 2026|8 min read

WordPress Multisite Shows 'Error Establishing a Database Connection' After Migration, But the Database Is Fine

Credentials correct, MySQL running, tables intact. The real cause was a domain mismatch in wp_site and wp_blogs that WordPress checks before it even tries to load your site.

S

Showrav Hasan

WordPress & Infrastructure Engineer

WordPressMultisiteMigrationDatabaseTroubleshooting
WordPress Multisite Shows 'Error Establishing a Database Connection' After Migration, But the Database Is Fine

TL;DR

If you migrated a WordPress Multisite and see "Error establishing a database connection" even though your credentials are correct and MySQL is running, check the wp_site and wp_blogs tables. They likely still have the old domain. WordPress Multisite looks up the requesting domain in these tables before it does anything else. If it does not find a match, it dies with a generic database error instead of telling you the domain is wrong.

-- Check what domain your multisite thinks it is
SELECT domain FROM wp_site;
SELECT blog_id, domain, path FROM wp_blogs;

-- Fix it
UPDATE wp_site SET domain='newdomain.com' WHERE domain='olddomain.com';
UPDATE wp_blogs SET domain='newdomain.com' WHERE domain='olddomain.com';

The Setup

A client migrated their WordPress Multisite from a production server to a staging environment on Rocket.net. The staging subdomain was staging123.onrocket.site. Standard migration: files synced, database imported, wp_options updated with the new URLs. Should have been straightforward.

The site loaded this:

Error Establishing a Database ConnectionError Establishing a Database Connection

No WordPress dashboard. No login page. Just the white screen with that one line of text.

Step 1: The Obvious Checks (All Passed)

First thing I did was pull up wp-config.php and confirm the database credentials:

define( 'DB_NAME', 'staging_prod' );
define( 'DB_USER', 'staging_prod' );
define( 'DB_PASSWORD', 'xK-mz39P(4' );
define( 'DB_HOST', 'localhost' );

Then tested the connection directly:

mysql -u staging_prod -p'xK-mz39P(4' -e "SELECT 1;"
+---+
| 1 |
+---+
| 1 |
+---+

Connection works. Credentials are correct.

Step 2: Table Integrity Check (Also Passed)

Maybe corrupted tables? Ran wp db check:

wp db check
staging_prod.wp_options          OK
staging_prod.wp_posts            OK
staging_prod.wp_postmeta         OK
staging_prod.wp_users            OK
staging_prod.wp_usermeta         OK
staging_prod.wp_blogs            OK
staging_prod.wp_site             OK
...
Success: Database checked.

Every single table returned OK. Over 180 tables across 5 subsites, all clean. If you want to know what the standard troubleshooting workflow looks like for this error, I covered the full process in my database connection error guide.

Step 3: Looking for Drop-in Overrides

WordPress has a little-known feature called "drop-in plugins." A file named db.php inside wp-content/ can completely override the database connection logic. If someone left a broken one behind, it would explain why CLI works but the web frontend does not.

ls -la wp-content/db.php
ls: cannot access 'wp-content/db.php': No such file or directory

No drop-in. Another dead end.

Step 4: The Clue That Changed Everything

At this point, I tried a different WP-CLI command. Instead of wp db check (which only tests the raw MySQL connection), I ran something that needs WordPress to fully bootstrap:

wp theme list
Error: Site 'staging123.onrocket.site/' not found.
Verify DOMAIN_CURRENT_SITE matches an existing site or use --url=<url> to override.

That was the real error. WordPress was telling me it could not find a site matching the domain staging123.onrocket.site in its Multisite tables. But on the web frontend, this same problem just shows the generic "Error establishing a database connection" message. No hint. No useful context. Just a misleading error.

Step 5: Finding the Domain Mismatch

Time to check what domain was actually stored in the database:

wp db query "SELECT domain FROM wp_site;" --skip-plugins --skip-themes
domain
clientsite.com
wp db query "SELECT domain FROM wp_blogs WHERE blog_id=1;" --skip-plugins --skip-themes
domain
clientsite.com
wp db query "SELECT option_value FROM wp_options WHERE option_name IN ('siteurl','home');" --skip-plugins --skip-themes
option_value
https://staging123.onrocket.site
https://staging123.onrocket.site

There it was. The wp_options table had the correct new domain (staging123.onrocket.site), but the Multisite network tables (wp_site and wp_blogs) still had the old production domain (clientsite.com).

Why This Breaks Everything

Here is how WordPress Multisite processes an incoming request:

  1. A browser hits staging123.onrocket.site
  2. WordPress loads wp-config.php and sees DOMAIN_CURRENT_SITE is staging123.onrocket.site
  3. WordPress queries wp_site for a row matching that domain
  4. No match found. The wp_site table still says clientsite.com
  5. WordPress cannot determine which network this request belongs to
  6. It bails out with "Error establishing a database connection"

The database connection itself is perfectly fine. WordPress never even gets to the point of loading your site content. It fails at the network lookup stage and throws a generic error that points you in completely the wrong direction.

The wp_options table (which stores siteurl and home) only gets checked after the Multisite network is identified. So updating wp_options alone does nothing if wp_site and wp_blogs still have the old domain.

Step 6: The Fix

Two SQL updates:

wp db query "UPDATE wp_site SET domain='staging123.onrocket.site' WHERE domain='clientsite.com';" --skip-plugins --skip-themes
wp db query "UPDATE wp_blogs SET domain='staging123.onrocket.site' WHERE domain='clientsite.com';" --skip-plugins --skip-themes

Site came back immediately. No restart needed, no cache clearing. The moment those two tables had the correct domain, WordPress could find the network and everything loaded.

The Right Way to Migrate a WordPress Multisite Domain

If you are doing a domain change during a Multisite migration, update these tables in this order:

1. Network tables (most people forget these)

UPDATE wp_site SET domain='newdomain.com' WHERE domain='olddomain.com';
UPDATE wp_blogs SET domain='newdomain.com' WHERE domain='olddomain.com';

2. Main site options

UPDATE wp_options SET option_value='https://newdomain.com'
WHERE option_name IN ('siteurl', 'home');

3. Network-level options

UPDATE wp_sitemeta SET meta_value='https://newdomain.com/'
WHERE meta_key='siteurl';

4. Subsite options (for each subsite)

UPDATE wp_2_options SET option_value='https://newdomain.com/subsite/'
WHERE option_name IN ('siteurl', 'home');
-- Repeat for wp_3_options, wp_4_options, etc.

5. Full search-replace for serialized data

wp search-replace 'olddomain.com' 'newdomain.com' --network --skip-columns=guid

This handles serialized data in post meta, widget settings, and theme options that a raw SQL REPLACE would corrupt.

6. Update wp-config.php

define( 'DOMAIN_CURRENT_SITE', 'newdomain.com' );

If you are migrating files with rsync and want to avoid a different class of migration pitfalls, check out my article on the rsync exclude trap that breaks plugin migrations.

Why WP-CLI Masked the Problem

One more thing worth noting. My initial WP-CLI commands (wp db check, wp db query) all worked fine. That is because these commands only need a raw MySQL connection. They do not bootstrap WordPress fully, so the Multisite domain lookup never happens.

It was only when I ran a command that requires full WordPress initialization (wp theme list) that the real error surfaced. If you are debugging a Multisite issue, always try a command that forces full bootstrap. wp option get siteurl or wp theme list are good choices. Do not rely on wp db check to confirm that "WordPress works."

The Takeaway

"Error establishing a database connection" on a WordPress Multisite after migration almost certainly means the wp_site and wp_blogs tables still have the old domain. The error message is misleading. The database connection is fine. WordPress just cannot find your network.

Check wp_site first. That is the table 99% of migration guides skip.


Frequently Asked Questions

Why does WordPress show "Error establishing a database connection" instead of "site not found" for a domain mismatch?

WordPress Multisite's early bootstrap process does not differentiate between a failed MySQL connection and a failed network lookup. Both conditions trigger the same generic error handler in wp-includes/ms-settings.php. The code checks for the network matching the incoming domain, and if it fails, it calls wp_die() with the database error message regardless of the actual cause.

Can I use WP-CLI to fix the domain in wp_site and wp_blogs if the site is down?

Yes. Use wp db query with the --skip-plugins --skip-themes flags. This command only needs a raw MySQL connection and does not require WordPress to fully load. You can run UPDATE queries directly against wp_site and wp_blogs even when the frontend is showing the database error.

What is the difference between wp_site, wp_blogs, and wp_options in a Multisite installation?

wp_site stores the network definition (one row per network, containing the primary domain). wp_blogs stores individual site registrations within the network (one row per subsite, each with its own domain and path). wp_options stores per-site settings like siteurl and home. During a domain change, all three must be updated. WordPress checks them in that order: network first, then site, then options.

Will wp search-replace fix the wp_site and wp_blogs tables automatically?

wp search-replace with the --network flag will update wp_options and content tables across all subsites, but it does not touch wp_site or wp_blogs. These are network-level tables that must be updated manually with direct SQL queries before wp search-replace will even work, because WordPress needs a valid network to bootstrap.

Do I need to update wp-config.php DOMAIN_CURRENT_SITE when migrating to a new domain?

Yes. The DOMAIN_CURRENT_SITE constant in wp-config.php must match the domain column in wp_site. WordPress uses this constant to look up the correct network record. If wp-config.php says newdomain.com but wp_site says olddomain.com, the lookup fails and you get the database error.

How do I handle subsite domains in wp_blogs during a migration?

Each subsite has its own row in wp_blogs with a domain column. For subdirectory installs, all subsites share the same domain but have different path values (like /blog/, /shop/). For subdomain installs, each subsite has its own domain. Update all rows in wp_blogs to reflect the new domain, then update each subsite's options table (wp_2_options, wp_3_options, etc.) with the correct siteurl and home values.

S

Written by Showrav Hasan

WordPress & Infrastructure Engineer with 3,500+ resolved incidents across Rocket.net, Hostinger, and NameSilo. I write about the troubleshooting workflows, server strategies, and engineering decisions behind real production support.

Need hands-on help with this?

I use these same strategies to resolve critical incidents for production WordPress sites.