SQLSTATE[HY000] [2002] Connection refused (SQL: select * from `posts`) with sail docker container

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company
# Cracking the Code: Solving SQLSTATE[HY000] Connection Refused in Laravel Sail Docker Environments As developers, we often find ourselves wrestling with environments that seem perfectly configured on the surface but throw cryptic errors when running complex application logic. The scenario you’ve described—where basic commands work, database tools connect fine, but a web request (like fetching data in a Controller) results in a `SQLSTATE[HY000] [2002] Connection refused` error within a Laravel Sail Docker setup—is an incredibly frustrating, yet surprisingly common, issue. This post dives deep into why this happens and provides the practical steps required to diagnose and resolve connection refusals when working with Laravel and Docker containers. ## The Paradox: Why Does It Work in Tinker but Fail in the Controller? You have established a critical distinction here: 1. **`php artisan migrate` & `php artisan tinker` work:** This confirms that the initial setup, database credentials, and the underlying MySQL service *are* accessible to the command-line environment. 2. **Web routes fail (`Post::all()`):** This indicates that the application process running under the web server (PHP-FPM container) cannot establish a stable network connection to the MySQL container at runtime. The difference usually lies not in the database itself, but in how the networking is handled between the different services within your Docker Compose setup and how Laravel resolves its hostnames. ## Deep Dive into Docker Networking Issues When dealing with Dockerized applications, the most frequent culprit for "Connection refused" errors in application code is an incorrect assumption about the hostname or a timing issue related to service startup. ### 1. Re-evaluating `DB_HOST` and Network Names In your setup, you correctly set `DB_HOST=127.0.0.1` in your `.env`. While this often works on a single host, inside a Docker network where services communicate via service names (like `mysql`), using `127.0.0.1` can sometimes be misleading or cause routing issues between containers. The best practice within a Docker Compose network is to use the **service name** defined in your `docker-compose.yml` file as the hostname. Since you have named your database service `mysql`, Laravel should ideally connect to it using that name rather than an IP address, allowing Docker's internal DNS resolution to handle the routing seamlessly. **Actionable Fix:** Change your `.env` file from: ```env DB_HOST=127.0.0.1 ``` To use the service name defined in `docker-compose.yml`: ```env DB_HOST=mysql ``` ### 2. Ensuring Service Readiness (The Healthcheck Factor) You have correctly implemented `healthcheck` definitions for your MySQL service in `docker-compose.yml`. This is excellent practice! However, sometimes the application container initializes and attempts to connect *before* the database container has fully initialized its listening ports, even if the services are listed as `depends_on`. While Laravel Sail handles a lot of this automatically, explicitly pausing or adding a wait mechanism can resolve timing-related connection refusals. Ensure that your web service has adequate time to wait for the database to be truly ready before executing heavy queries. ### 3. Reviewing the `docker-compose.yml` Configuration Your provided `docker-compose.yml` looks robust, defining necessary networks and volumes correctly. The key interaction point is ensuring that all services are on the same shared network (`sail` in your case). If you were running this outside of Sail (without the managed environment), manually verifying firewall rules or port exposure would be crucial, but within Sail, focusing on the hostname (Step 1) is usually the fix. ## Conclusion: The Developer Mindset for Docker Debugging Debugging containerized applications requires shifting your mindset from "What is wrong with the code?" to "How is the network communicating between these isolated processes?" When you encounter `Connection refused` errors in a Laravel/Docker context, always follow this hierarchy of investigation: 1. **Hostname Check:** Is `DB_HOST` set to the correct service name (e.g., `mysql`) rather than an IP address? 2. **Networking Check:** Are all services correctly attached to the same Docker network? 3. **Readiness Check:** Does the application wait for the database service to be fully operational before attempting a connection? By applying these principles, you move from guessing about obscure errors to systematically diagnosing environment configuration issues, ensuring your Laravel application can communicate reliably with its underlying data store. For more advanced insights into building robust Laravel applications, exploring best practices detailed on [laravelcompany.com](https://laravelcompany.com) is highly recommended.