TechEarl

How to Fix "Error Establishing a Database Connection" in WordPress

Error establishing a database connection means WordPress cannot reach its database. Read the MySQL error code to find the real cause (wrong credentials, a stopped server, a connection limit, corrupted tables, or a cloud firewall) and fix that one thing.

Ishan Karunaratne⏱️ 13 min readUpdated
Share thisCopied
How to fix the WordPress error establishing a database connection by reading the MySQL error code to find the real cause

"Error establishing a database connection" means exactly what it says: WordPress loaded, tried to talk to its MySQL or MariaDB database, and could not. Every page shows it, including /wp-admin, because nothing renders without the database. (One useful exception: if WordPress can connect but a table is corrupted, the front end still shows this error while /wp-admin shows a different message about tables needing repair, which points you straight at corrupted tables.) The message is otherwise the same no matter why the connection failed, which is why people thrash around editing random files. Do not. The real cause is almost always one of five things, and the database itself will tell you which one if you ask it directly.

First, find out which failure it is

Before you change anything, test the connection the way WordPress does, straight from the command line, and read the error code. Use the same credentials that are in wp-config.php:

bash
mysql -h DB_HOST -u DB_USER -p DB_NAME -e 'SELECT 1'

The number it returns is the whole diagnosis:

MySQL client returning ERROR 1045 for wrong credentials, ERROR 2003 (111) for a stopped server, and ERROR 1040 for too many connections
The MySQL error number names the cause. Fix that one thing, not random files.
What you seeWhat it meansGo to
ERROR 1045 ... Access deniedWrong user or passwordCredentials
ERROR 2003 ... (111) (refused)Server down, or wrong DB_HOST / portServer down
ERROR 2003 ... (110) (timed out)A firewall or security group is dropping the connectionCloud databases
ERROR 2005 ... Unknown server hostDB_HOST is a typo, or DNS cannot resolve itCredentials
ERROR 1040 ... Too many connectionsThe server is up but out of connection slotsToo many connections
ERROR 144 / 145 / "marked as crashed"A table is corruptedCorrupted tables

This works the same against MySQL or MariaDB; the error numbers are identical. If the command succeeds and returns 1, the connection details themselves are valid (SELECT 1 proves the login and database selection worked, though not that every table is intact). The problem is then one of two things: wp-config.php is pointing WordPress at a different database than the one you just tested, or a stale copy of the error is stuck in a cache (see the cached-error case below).

One thing that will not help, despite being all over the internet: raising the PHP memory limit. A database connection failure is a credentials or networking problem, not a memory one, so leave WP_MEMORY_LIMIT out of it.

No shell access? Run the same test from a browser. Put this in a file like db-test.php in your site root, copy the four values from wp-config.php, load the file once, and then delete it (it prints your database error and must not stay public):

php
<?php
// db-test.php — fill in your wp-config values, load in a browser, then delete this file.
$link = @mysqli_connect( 'DB_HOST', 'DB_USER', 'DB_PASSWORD', 'DB_NAME' );
echo $link
    ? 'OK: connected.'
    : 'FAILED (' . mysqli_connect_errno() . '): ' . mysqli_connect_error();

The number in FAILED (1045) is the same error code as the table above, so the diagnosis is identical whether you use the command line or the browser.

Cause 1: Wrong database credentials

This is the most common one, and the fix is direct: if the mysql test returns ERROR 1045, the username or password is wrong, so reset it and update wp-config.php to match. WordPress reads four constants from wp-config.php; check what they actually are:

wp config get showing DB_HOST, DB_USER and DB_NAME, then a successful SELECT 1 after the credentials are corrected
Read the four constants, then re-run the same connection test until it returns 1.
php
// wp-config.php
define( 'DB_NAME', 'your_database' );
define( 'DB_USER', 'your_user' );
define( 'DB_PASSWORD', 'your_password' );
define( 'DB_HOST', 'localhost' );

A few things that quietly break this:

  • A rotated or mistyped password. Paste the exact DB_PASSWORD into the mysql test above. If you get ERROR 1045, the password (or user) is wrong, full stop. Reset it in your host's control panel or with ALTER USER 'your_user'@'host' IDENTIFIED BY 'new_password'; and update wp-config.php to match.
  • An unescaped quote or backslash in the password. DB_PASSWORD is a single-quoted PHP string, so a literal ' has to be written \' and a literal \ written \\. A $ or a backtick is safe inside single quotes, but an unescaped quote breaks the line entirely. If in doubt, regenerate a password without quotes or backslashes.
  • DB_HOST is not always localhost. localhost connects over a Unix socket; 127.0.0.1 forces TCP; a remote or managed database needs hostname:port or hostname:/path/to/socket. Some hosts use a non-localhost value like mysql.yourhost.com. If you migrated the site, this is the field that is most often stale.

After a migration, also confirm the database actually exists on the new server and the user has rights to it: SHOW DATABASES; and SHOW GRANTS FOR 'your_user'@'host';.

On cPanel hosting you do the same checks in the GUI: MySQL Databases shows the database name and lets you reset the user's password (then update DB_PASSWORD to match), and phpMyAdmin confirms the database and its tables are actually there. The cause is identical; only the tooling differs.

Cause 2: The database server is down

If the test returns ERROR 2003 ... (111), the host is reachable but nothing is answering on the database port. Usually the MySQL or MariaDB service has stopped. Check it and start it:

bash
systemctl status mysql      # or: systemctl status mariadb
sudo systemctl start mysql

If it refuses to start, read the log (/var/log/mysql/error.log or journalctl -u mysql). The most common reason a database will not start, by a wide margin, is a full disk. MySQL cannot write its files and dies on boot. Check with df -h; if the data partition is at 100%, clear space (old logs, backups, the binary logs under the data directory) and start the service again. A close second is a crash that left the data directory needing recovery, which the error log will spell out.

On shared hosting you cannot restart the service yourself. A 2003/refused error there means the host's database server is down or overloaded, and the fix is a support ticket, not a config edit.

Cause 3: Too many connections

ERROR 1040 (HY000): Too many connections means the server is healthy but every connection slot is in use, so WordPress is turned away. MySQL allows max_connections clients at once (151 by default), plus one reserved slot for an admin.

The quick way to breathe is to restart the database, which drops every stuck connection. That clears the symptom but not the cause. What actually fills the slots:

  • A traffic spike (real visitors, or a bot crawl) beyond what the server is sized for.
  • Slow queries holding connections open. One missing index on a busy query can pin connections for seconds each, and they stack up.
  • A plugin or a bad bit of code opening connections without closing them.

Look at what is actually connected with SHOW PROCESSLIST; (or SHOW FULL PROCESSLIST;). If you see dozens of identical queries in Sending data, that query is your problem; fix the query or add the index. If the list is full of connections from one plugin that never closes them, isolate it: rename wp-content/plugins to plugins.off to disable everything at once, confirm the connection count drops, then move plugins back one at a time until the culprit reappears. If the box genuinely needs more headroom and has the RAM for it, raise the limit:

sql
SET GLOBAL max_connections = 300;   -- until restart

Make it permanent in my.cnf under [mysqld], but only raise it if the server has the memory; every connection costs RAM, and setting it too high just trades one crash for another.

Cause 4: Corrupted database tables

If the error mentions a specific table being "marked as crashed" or you see ERROR 144/145, a table is corrupted, usually after an unclean shutdown or a disk problem. WordPress has a built-in repair tool. Add this to wp-config.php, just above the "That's all, stop editing" line:

php
define( 'WP_ALLOW_REPAIR', true );

Then visit https://yoursite.com/wp-admin/maint/repair.php directly. It does not require a login (that is the point, since you are locked out), and it offers "Repair Database" and "Repair and Optimize Database." Run it, then remove that line from wp-config.php immediately, because leaving the repair page open to the public is a real risk.

From the command line, the equivalent is:

bash
wp db repair                                  # WP-CLI
# or, against the server directly (one database, then widen if needed):
mysqlcheck -u DB_USER -p --auto-repair DB_NAME

On cPanel, repair without touching files: in phpMyAdmin, open the database, tick all tables, and choose Repair table from the "With selected" dropdown; some hosts also expose a "Repair Database" button in cPanel itself.

If repair cannot fix it, restoring the affected table (or the whole database) from your last good backup is the reliable path. This is the moment you find out whether your backups actually work.

Managed and cloud databases (AWS RDS, Google Cloud SQL)

When the database is a managed service (Amazon RDS, Aurora, Google Cloud SQL, Azure Database) and the app is on a separate server, the failure mode shifts from "the database is broken" to "the network between them is blocked." The tell is the OS code inside the 2003 error:

ERROR 2003 (111) connection refused versus ERROR 2003 (110) timed out, distinguishing a stopped service from a firewall or security group block
111 = refused (nothing listening). 110 = timed out (packets dropped, almost always a firewall or security group).

A timed-out (110) connection to a cloud database is almost never the database itself. It is the network path. The usual suspects:

  • Security group / firewall rules. The RDS instance's security group must allow inbound 3306 from the web server's security group or IP. This is the number-one cause of a brand-new RDS connection timing out. On Google Cloud SQL the equivalent is authorized networks (for public IP) or running the Cloud SQL Auth Proxy / using a private IP inside the VPC.
  • Public versus private IP. If your app connects over a private IP, it has to be in the same VPC (or a peered one). Pointing DB_HOST at a private endpoint from outside the VPC just times out.
  • The instance is stopped or in maintenance. RDS instances can be stopped manually (and auto-start after 7 days), and an instance that filled its storage goes into a storage-full state and stops accepting writes. Check the instance status in the console.
  • A stale endpoint. If you restored from a snapshot or recreated the instance, the endpoint hostname changed. The old DB_HOST in wp-config.php now points at nothing. (A plain reboot or a Multi-AZ failover keeps the same endpoint, so those do not cause this.)
  • max_connections is set by instance size. On RDS the default is derived from the instance class memory, not 151, and you change it through the parameter group, not my.cnf. A small instance under load hits 1040 quickly.
  • TLS required, or rotated credentials. If the instance requires TLS, a non-TLS session is rejected during the handshake (you get an SSL or authentication error from MySQL, not a port-refused timeout). And if credentials live in Secrets Manager or you use IAM authentication, a rotation the app did not pick up looks exactly like a wrong password.

So on cloud: a 1045 is still credentials, a 1040 is still connection limits (sized by your tier), but a timeout points you at security groups and networking, not at WordPress.

Fixed it but the error won't go away?

If the connection test above returns 1 (the database is healthy) yet visitors still see the error, the database is not your problem anymore: a stale copy of the error page is stuck in a cache and is being served after recovery. That happens when the error came back as an HTTP 200 and a page cache, server cache, or CDN stored it. It is a distinct problem with a distinct fix, which I covered in detail in "Error establishing a database connection" stuck in cache. The short version is to purge the cache and make your wp-content/db-error.php return a 503 so it can never be cached again.

Stop it happening again

Two things cause almost every one of these outages, and both are silent until they take the site down: the database server running out of disk, and the connection count reaching max_connections. Alert on both. Once the site is back, a few habits keep this from recurring:

  • Watch the two things that actually cause it: free disk on the database server, and connection count against max_connections. Both are trivial to alert on, and both are silent until they take the site down.
  • Size the database for real traffic. Most "too many connections" outages are an undersized instance plus one slow query. Find the slow query.
  • Make outages cache-safe. A wp-content/db-error.php that returns a 503 (see the cached-error guide) means a brief database blip never gets immortalized in a cache.
  • Test your backups. Corruption and a full disk are the two cases where a working restore is the only real fix. A backup you have never restored is a guess.

Sources

Authoritative references this article was fact-checked against.

TagsWordPressDatabaseMySQLMariaDBAWS RDSTroubleshooting

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Software Systems Architect · Senior Software Engineer · Engineering Leadership

Software systems architect and senior software engineer with more than two decades designing, building, and running production software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Now a CTO, though what I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts