Error establishing a database connection means WordPress read wp-config.php, tried to reach MySQL with what it found there, and failed. That single sentence covers four genuinely different problems: wrong credentials, a database server that is down, a server that is up but refusing this connection, or a corrupted database.
The error text is identical in all four cases, which is why guessing is slow and testing is fast. The whole diagnosis takes about two minutes if you do it in the right order, and the first step is to make WordPress tell you more than it does by default.
Table of contents
- Make the error say something useful first
- Check the four credentials against reality
- When the credentials are right
- Repairing a corrupted database
- The version of this that is a hosting problem
- Preventing the next one
- How this fits the rest of the stack
- FAQ
Make the error say something useful first
By default WordPress swallows the underlying MySQL error and shows you the generic string. Turn that off before you change anything else. In wp-config.php, above the line that says to stop editing:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Reload the site, then read wp-content/debug.log. The real MySQL error is in there, and it usually names the problem outright:
- Access denied for user — credentials are wrong, or the user lacks rights on that database.
- Can’t connect to MySQL server — the host is unreachable, or the service is not running.
- Unknown database — the user and password are fine but the database name does not exist.
- Too many connections — the server is up and at its connection limit.
Setting WP_DEBUG_DISPLAY to false keeps the detail out of the page your visitors see while still writing it to the log. Do not skip that part on a live site.
Turn all three back off once you are done. A world-readable debug.log on a production site is an information disclosure problem.
Check the four credentials against reality
If the log says access denied or unknown database, the answer is in these four lines of wp-config.php:
define( 'DB_NAME', 'your_database_name' );
define( 'DB_USER', 'your_database_user' );
define( 'DB_PASSWORD', 'your_password' );
define( 'DB_HOST', 'localhost' );
Verify them against the database rather than against memory. Test the exact values from the command line on the same machine:
mysql -u your_database_user -p -h localhost your_database_name
If that connects, WordPress can too, and your problem is elsewhere — usually a stray space or an unescaped character inside the quotes in wp-config.php. If it fails, you have reproduced the fault outside WordPress, which is a much better place to fix it.
The two that go wrong most often are DB_HOST and DB_PASSWORD. DB_HOST is localhost on many shared hosts and a specific hostname or IP on managed database services — copying a config between environments without changing it is the classic cause. DB_PASSWORD breaks when it contains characters that need escaping in a single-quoted PHP string, particularly backslashes and single quotes.
When the credentials are right
If the manual mysql connection works and WordPress still fails, work through these in order:
- Check the table prefix. $table_prefix in wp-config.php must match the actual tables. If your tables are wp_3f_options and the config says wp_, WordPress connects successfully and then finds nothing, which sometimes surfaces as this error and sometimes as a broken install screen.
- Check for authentication plugin mismatch. MySQL 8 defaults to caching_sha2_password. Older PHP MySQL clients only speak mysql_native_password. This produces access denied with correct credentials, which is maximally confusing. Fix by altering the user to use mysql_native_password, or by updating the PHP client.
- Check connection limits. If the log said too many connections, the credentials are irrelevant — the server is refusing new connections because existing ones are not being released. Look for a plugin opening connections in a loop, or simply a limit set too low for your traffic.
- Check disk space on the database host. A full disk makes MySQL refuse connections in ways that look like almost anything else. df -h takes two seconds and rules it out.
That MySQL 8 authentication issue deserves its own note because it appears after a host upgrades the database and nothing on your side changed. The site was working, nobody touched it, and now it is down. The cause is a version bump you did not make.
Repairing a corrupted database
If the log points at a corrupt or crashed table, WordPress has a built-in repair mode. Add to wp-config.php:
define( 'WP_ALLOW_REPAIR', true );
Then visit /wp-admin/maint/repair.php on your site. That page does not require login — which is exactly why you must remove the constant from wp-config.php the moment you are finished. Leaving it in place is a live vulnerability.
The equivalent from the command line, which is faster and does not open a public endpoint:
mysqlcheck -u your_database_user -p --auto-repair --check your_database_name
Table corruption on a modern InnoDB setup is uncommon and usually means something worse happened underneath — an unclean shutdown, a full disk, or failing storage. Repairing the table fixes the symptom. Find out what caused it, or you will be repairing it again.
The version of this that is a hosting problem
A meaningful share of these errors are not configuration at all. The database server is genuinely down, out of memory, or has been restarted by the host, and there is nothing in wp-config.php to fix.
You can tell these apart quickly. If the manual mysql command from the same server fails with a connection error rather than access denied, WordPress is not the problem. If the site recovers on its own after a few minutes and then fails again later, you are looking at a resource limit being hit under load rather than a broken setting.
The recurring version of this — fine at low traffic, breaks under load, recovers when traffic drops — is almost always connection exhaustion or the database being starved of memory. Restarting makes it go away for a while, which is why it tends to get restarted rather than diagnosed.
That is the point at which the database being managed rather than co-located starts to matter. A database with a visible connection limit and its own memory allocation fails in ways you can read, rather than taking the whole box down with the web server.
Preventing the next one
Three habits that remove most repeat occurrences:
- Keep credentials out of the codebase. wp-config.php in version control means a database password in git history and a config that has to be edited by hand per environment. Environment variables move the value out of the file.
- Know your connection limit and your actual concurrency. If you have never looked at either number, you cannot tell whether an outage under load was a spike or a leak.
- Test a restore. Not a backup — a restore. Most people discover their backups are unusable during the incident that needs them.
The last one is the least fun and the most valuable. Database corruption and accidental deletion are the two failures where the fix is entirely determined by what you did beforehand.
How this fits the rest of the stack
The frustrating part of this error is that the message is the same whether you mistyped a password or your database server ran out of memory, so the first two minutes are spent working out which failure you have. Managed MySQL and Postgres on RunxBuild expose the connection limit, the backups, and the user list as things you can look at rather than infer, and WordPress on RunxBuild includes a database browser in the dashboard, so checking a table prefix does not mean finding phpMyAdmin credentials first. When you are sizing the site and its database together, the RunxBuild hosting calculator shows them as separate line items.
Useful related references:
- SSH Establishing Connection Stuck: 6 Causes and the Right Fix
- Deploy WordPress for Free on RunxBuild
- WordPress Self-Hosting: LAMP, Docker, or Managed RunxBuild
- Databases on RunxBuild
FAQ
How do I see the real MySQL error behind this message?
Set WP_DEBUG and WP_DEBUG_LOG to true and WP_DEBUG_DISPLAY to false in wp-config.php, reload the site, and read wp-content/debug.log. The underlying error names the actual problem. Turn all three off again afterwards.
Why does it say access denied when my password is correct?
Most often a MySQL 8 authentication mismatch: the server defaults to caching_sha2_password and an older PHP client only speaks mysql_native_password. It also happens when the password contains a backslash or quote that is not escaped inside the single-quoted PHP string.
What should DB_HOST be set to?
localhost on most shared hosting where the database runs on the same machine, or a specific hostname or IP for a managed database service. Copying a wp-config.php between environments without updating DB_HOST is a very common cause of this error.
Is WP_ALLOW_REPAIR safe to leave enabled?
No. It exposes /wp-admin/maint/repair.php without requiring a login. Add the constant, run the repair, then remove it immediately. Leaving it in place is a live vulnerability on a public site.
Why does the error come and go under traffic?
That pattern points at connection exhaustion or the database being starved of memory rather than a configuration problem. The site recovers when concurrency drops and fails again when it rises. Check your connection limit against actual concurrent usage.