You just moved your site to a new server and now you're staring at some variation of SQLSTATE[HY000] [2002] Connection refused. It's frustrating because everything else seems fine. Let me save you the rabbit hole of checking MySQL logs first.
The Fix: Change the Host in Your Config File
Open your database config file. Where that lives depends on your stack:
- WordPress —
wp-config.php - Laravel —
.env - Drupal —
settings.php - Custom PHP — wherever you defined
$db_host
Look for the DB_HOST or host setting. If it says localhost or an old IP address, change it to the new server's hostname or IP. On most managed hosts (like DigitalOcean, AWS RDS, or shared hosting), the host will be a socket path or an internal IP like 10.0.0.4. Use whatever your new provider gave you.
Then clear any application cache. For Laravel:
php artisan config:cache
php artisan cache:clear
For WordPress, you usually don't need to clear a cache, but if you're using a page cache plugin like W3 Total Cache, flush it. Some environments also cache DNS — on your server run systemctl restart nscd or reboot.
Why This Works
What's actually happening here is that your application is trying to connect to the database at the old location. The config file is the first place the app checks. If it still says localhost, MySQL on the new server might not even be listening on TCP (it often uses a Unix socket instead), or the old IP is now dead. Changing the host to the correct value — usually the socket path like /var/run/mysqld/mysqld.sock on Linux — tells the app where to find the real database.
The reason step 3 works (clearing cache) is that Laravel and similar frameworks cache config in bootstrap/cache/config.php. That file doesn't regenerate on every request — it sits there with the old host until you explicitly clear it. Without that, you'd edit .env, restart the server, and still get the same error because the cache is stale.
Also, some hosts use 127.0.0.1 vs localhost — they sound the same but aren't. localhost typically uses a Unix socket, 127.0.0.1 forces TCP. If your new server's MySQL only listens on a socket, 127.0.0.1 will fail. Try switching between them if the first attempt doesn't work.
Less Common Variations of the Same Issue
1. The Database User Doesn't Have Access from the New IP
Even if the host is correct, MySQL might reject the connection because the user is restricted to a specific IP. Check with your host's database admin panel — the user's host field should be % (any host) or your app server's IP. Most MySQL errors here show Access denied for user not Connection refused, but I've seen shared hosts that return 2002 when the user is misconfigured.
2. Firewall Blocking Port 3306
If you're connecting to a remote database (like RDS), the security group or iptables on the new server might block outgoing traffic to port 3306. Test with:
telnet your-db-host.com 3306
If it hangs or says Connection refused, the firewall is the problem. On Ubuntu, check sudo ufw status. On RDS, check the inbound rules in the security group attached to the database instance.
3. The MySQL Service Isn't Running
This one's obvious but easy to miss after a migration. SSH into the database server and run:
sudo systemctl status mysql
If it's dead, sudo systemctl start mysql and sudo systemctl enable mysql to start on boot. Some migration scripts forget to start the service after a restore.
4. The Database Name Changed
You changed the database name during migration but forgot to update the config. Check DB_DATABASE in your .env or equivalent. A wrong database name returns Unknown database but sometimes gets lumped under generic 2002 errors in older frameworks.
Preventing This Next Time
Before you migrate, write down the exact database host, port, database name, user, and password from the old environment. Then on the new server, create the database, user, and grant permissions before you move the app code. Test the connection from the app server using the MySQL CLI:
mysql -h new_host -u username -p database_name
If that connects, your app will too — assuming the config is right.
Also, use environment variables for sensitive config values, not hardcoded files. That way you only change one place (the .env file) and never leave old passwords in your codebase. Version control your .env.example but never the actual .env — that's how you get burned.
Finally, automate this. A simple shell script that runs before your app boots can check that the database host is reachable and the user can authenticate. It's ten lines of bash and saves you from the 2 AM panic when the migration goes wrong.