That “Connection Refused” Error Ruined My Monday Morning, Here’s Every Fix I Actually Tried

I opened my laptop on a Monday morning, pulled the latest code for a client project, ran php artisan migrate, and got hit with this wall of red text:
SQLSTATE[HY000] [2002] Connection refused
Nothing had changed on my end since Friday. Same laptop, same project, same everything. I genuinely stared at it for a solid minute, refreshed, tried again, same error. Classic “it worked on Friday” situation that every developer knows a little too well.
Turns out, over the weekend my laptop had done a routine Windows update, and that somehow reset a couple of background services, including MySQL, which just wasn’t running anymore. Simple fix once I found it, but it took me almost 40 minutes of digging through unrelated fixes first because I assumed it was something complicated with Laravel itself.
If you’ve hit this exact error and you’re not sure where to even start looking, here’s every actual cause I’ve personally run into across different projects, roughly in the order I’d check them now.
What This Error Actually Means (In Plain Terms)
This error basically just means Laravel tried to talk to your database, and nobody picked up the phone. It’s not Laravel’s fault directly, it’s saying “I tried connecting to the database server at the address and port you gave me, and nothing responded.”
The actual cause could be your database server not running at all, wrong connection details in your .env file, a firewall blocking the connection, or in some cases, Docker containers not talking to each other properly. Let’s go through each one.
Fix 1: Check If Your Database Server Is Actually Running
This sounds almost too obvious, but it’s genuinely the most common cause, and it’s exactly what happened to me that Monday morning.
If you’re using XAMPP (which I still use for a lot of local client projects since it’s simple and most junior devs I mentor are already familiar with it), open the XAMPP control panel and check if MySQL shows a green “Running” status.
# On Windows, checking via command prompt
sc query mysql
If you’re on Mac or Linux using a native MySQL install:
sudo service mysql status
Or if you’re using MySQL through Homebrew on Mac:
brew services list
In my case, MySQL showed as “Stopped” in the XAMPP panel. Clicked “Start,” waited three seconds, ran the migration again, worked perfectly. Forty minutes of unrelated troubleshooting for something that took three seconds to actually fix.
Fix 2: Double Check Your .env Database Settings
If your database server is confirmed running but you’re still getting this error, check your .env file next.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=root
DB_PASSWORD=
I’ve made this mistake myself, using localhost instead of 127.0.0.1 for DB_HOST. On most setups these behave identically, but on certain configurations, especially some XAMPP and WAMP setups on Windows, localhost tries to connect through a socket file instead of TCP, and if that socket path is misconfigured, you’ll get this exact connection refused error even though MySQL is running perfectly fine.
Switching DB_HOST from localhost to 127.0.0.1 fixed this exact issue for me on a different project a while back, one where a teammate’s setup worked fine with localhost but mine didn’t, purely because of how our individual XAMPP installs handled socket connections differently.
After changing anything in .env, remember to clear Laravel’s cached config, since Laravel caches environment values and won’t pick up your changes otherwise:
php artisan config:clear
I’ve forgotten this step more times than I’d like to admit, changed the .env file, still got the same error, then realized Laravel was still reading the old cached config the whole time.
Fix 3: Check If You’re Using The Right Port
Default MySQL port is 3306, but I’ve worked on a few projects where a different local service was already using that port, forcing MySQL to run on something like 3307 instead, without me realizing it right away.
You can check what’s actually listening on port 3306:
# Windows
netstat -ano | findstr 3306
# Mac/Linux
lsof -i :3306
If nothing shows up, or something unexpected shows up on that port, that’s your clue. On one project, I had two different local development environments installed (an older XAMPP alongside a newer Laravel Herd setup), and their MySQL instances were fighting over the same port. Changing one of them to run on 3307 and updating that project’s DB_PORT in .env sorted it out.
Fix 4: If You’re Using Docker (This One Took Me A While To Understand)
This is where things got genuinely confusing for me the first time I hit this error inside a Dockerized Laravel setup using Laravel Sail.
Inside Docker, your DB_HOST shouldn’t be 127.0.0.1 or localhost at all. It needs to reference the actual service name defined in your docker-compose.yml file.
DB_HOST=mysql
Not 127.0.0.1, literally the word mysql, matching whatever your database service is named inside docker-compose.yml. I kept trying 127.0.0.1 out of habit from non-Docker projects and couldn’t figure out why it refused to connect, since from inside a container, 127.0.0.1 refers to the container itself, not your actual MySQL container sitting right next to it.
Once I understood Docker containers talk to each other through service names on an internal network, not through localhost, this stopped being confusing entirely.
Also worth checking, make sure your containers are actually up:
docker ps
If your MySQL container isn’t listed as running, that’s your answer right there. Sometimes a container fails to start due to a port conflict with a MySQL instance already running natively on your machine (yes, this happened to me too, running native MySQL and Docker’s MySQL container both trying to claim port 3306 at the same time).
Fix 5: Production Server Specific Causes
If this error is happening on a live production server rather than locally, the causes shift a bit.
Check if the database service crashed or restarted. SSH into your server and check:
sudo systemctl status mysql
If it’s not active, restart it:
sudo systemctl restart mysql
Check your firewall settings, especially if your database is hosted separately from your application server. If you’re using a managed database service (like DigitalOcean’s managed MySQL, which I’ve used for a couple of client projects), make sure your application server’s IP is actually whitelisted in the database’s trusted sources settings. I’ve been caught out by this exact thing after migrating a project to a new server and forgetting to update the database’s allowed IP list.
Check if you’ve hit your hosting plan’s connection limits. On a shared hosting plan for a smaller client project, I once ran into this error specifically during high traffic periods, turned out the hosting plan had a fairly low max connections limit, and once that got hit, new connection attempts were refused entirely. Upgrading to a plan with a higher connection limit resolved it, though for a bigger project, connection pooling or query optimization to reduce simultaneous connections would be the better long-term fix.
Step-By-Step Checklist I Actually Follow Now
After running into this error enough times across different projects, here’s the order I check things in now, roughly fastest-to-slowest:
- Is the database service actually running? (Check XAMPP panel,
systemctl status mysql, ordocker ps) - Did I run
php artisan config:clearafter any.envchanges? - Is
DB_HOSTcorrect for my environment? (127.0.0.1for local, service name for Docker, actual server IP for remote databases) - Is the port correct and not conflicting with another service?
- If production, is the firewall or IP whitelist blocking the connection?
Following this order has saved me from repeating that 40-minute Monday morning debugging session more than once.
Common Mistakes I’d Warn You About
Assuming it’s a Laravel bug. It almost never is. This error is Laravel accurately reporting that it genuinely couldn’t reach the database, the actual cause is almost always environmental.
Forgetting to clear config cache after editing .env. This one bites experienced developers just as often as beginners, myself included, more times than I’d like to admit.
Not checking if two local MySQL instances are conflicting. If you’ve got multiple local development tools installed (XAMPP, Laravel Herd, Docker, a native MySQL install), it’s worth actually checking which one is running and on which port before assuming your code or config is wrong.
Ignoring the database’s own error logs. On a stubborn case once, checking MySQL’s own log file (/var/log/mysql/error.log on a Linux server) revealed the actual database had run out of disk space and refused new connections as a result, something Laravel’s error message alone never would have told me.
Final Thoughts
This error looks scary the first time you see it, mostly because of how technical and vague “SQLSTATE[HY000] [2002]” sounds. In reality, it’s almost always something fairly simple, a stopped service, a wrong host value, or a port conflict, not some deep Laravel issue you need to rewrite code to fix.
Next time you hit this, resist the urge to immediately start googling Laravel-specific fixes and check if your database is actually running first. That single check would’ve saved me almost 40 minutes on a Monday morning I’d honestly rather not repeat.



