"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:
mysql -h DB_HOST -u DB_USER -p DB_NAME -e 'SELECT 1'The number it returns is the whole diagnosis:

| What you see | What it means | Go to |
|---|---|---|
ERROR 1045 ... Access denied | Wrong user or password | Credentials |
ERROR 2003 ... (111) (refused) | Server down, or wrong DB_HOST / port | Server down |
ERROR 2003 ... (110) (timed out) | A firewall or security group is dropping the connection | Cloud databases |
ERROR 2005 ... Unknown server host | DB_HOST is a typo, or DNS cannot resolve it | Credentials |
ERROR 1040 ... Too many connections | The server is up but out of connection slots | Too many connections |
ERROR 144 / 145 / "marked as crashed" | A table is corrupted | Corrupted 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
// 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.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_PASSWORDinto themysqltest above. If you getERROR 1045, the password (or user) is wrong, full stop. Reset it in your host's control panel or withALTER USER 'your_user'@'host' IDENTIFIED BY 'new_password';and updatewp-config.phpto match. - An unescaped quote or backslash in the password.
DB_PASSWORDis 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_HOSTis not alwayslocalhost.localhostconnects over a Unix socket;127.0.0.1forces TCP; a remote or managed database needshostname:portorhostname:/path/to/socket. Some hosts use a non-localhost value likemysql.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:
systemctl status mysql # or: systemctl status mariadb
sudo systemctl start mysqlIf 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:
SET GLOBAL max_connections = 300; -- until restartMake 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:
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:
wp db repair # WP-CLI
# or, against the server directly (one database, then widen if needed):
mysqlcheck -u DB_USER -p --auto-repair DB_NAMEOn 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:

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
3306from 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_HOSTat 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-fullstate 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_HOSTinwp-config.phpnow points at nothing. (A plain reboot or a Multi-AZ failover keeps the same endpoint, so those do not cause this.) max_connectionsis 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, notmy.cnf. A small instance under load hits1040quickly.- 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.phpthat returns a503(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.
- Common WordPress errors — WordPress.org documentationwordpress.org
- Editing wp-config.php — WordPress.org documentationwordpress.org
- MySQL client error reference (1045, 1040, 2002, 2003)dev.mysql.com
- Troubleshoot connecting to an Amazon RDS instance — AWSrepost.aws
- Connect to Cloud SQL for MySQL — Google Cloud documentationcloud.google.com





