Cannot access mysql database after migrating from Homestead to Sail

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Cannot Access MySQL Database After Migrating from Homestead to Sail: A Deep Dive into Docker Networking Errors

Migrating a Laravel project from a traditional environment like Homestead to the modern, containerized setup of Laravel Sail is often a step towards better scalability and reproducibility. However, this transition frequently introduces subtle networking or permission issues, particularly when dealing with database connections. The scenario you've described—being able to run the application but failing to connect to the MySQL database via the sail mysql command—is a classic symptom of misconfigured Docker networking or user permissions within the container environment.

As a senior developer, I can assure you that this isn't usually an issue with Laravel itself, but rather how the host system (your terminal) is resolving the hostname and connecting to the service running inside the Docker network. Let’s break down why this happens and how to fix it definitively.

Diagnosing the Access Denied Error

You encountered two distinct errors:

  1. ERROR 1045 (28000): Access denied for user 'myproject'@'localhost' (using password: YES)
  2. ERROR 1044 (42000): Access denied for user 'sail'@'%' to database 'myproject'

The first error implies the client tried to connect using localhost, which is often incorrect inside a Docker context where services communicate via internal network names, not the host machine address. The second error confirms that while the connection attempt was made successfully across the network (using % for any host), the MySQL user (sail) does not have the necessary privileges on the target database (myproject).

The key difference between Homestead and Sail lies in how networking is handled: Homestead uses a standard VM setup where localhost maps directly to the physical machine, whereas Sail relies entirely on Docker’s internal bridge network.

The Solution: Mastering Docker Networking for Laravel Sail

The solution lies in ensuring that your application container (where you run the sail command) correctly references the MySQL service using its defined Docker service name.

1. Correcting the Environment Variables

When working with Docker Compose, services communicate using the service names defined in the docker-compose.yml file as their hostnames. In your case, the MySQL service is named mysql.

The crucial change: You must set DB_HOST to the service name, not localhost.

Reviewing your .env file:

DB_CONNECTION=mysql
DB_HOST=mysql          # Change this from 'localhost' to the Docker service name
DB_PORT=3306
DB_DATABASE=myproject
DB_USERNAME=sail
DB_PASSWORD=password

By setting DB_HOST=mysql, you instruct your Laravel application (and any CLI commands interacting with it) to look for the database service on the Docker network, which resolves correctly to the MySQL container.

2. Reviewing the docker-compose.yml Configuration

Your docker-compose.yml file looks generally correct for setting up a standard persistence layer:

    mysql:
        image: 'mysql/mysql-server:8.0'
        # ... other settings ...
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'

The setup correctly defines the MySQL service and passes environment variables to it. The healthcheck is also a good practice for ensuring the database is ready before Laravel attempts connection, which aligns with robust application design principles advocated by organizations like Laravel Company.

3. Rebuilding and Restarting

After making changes to .env, you must always ensure Docker rebuilds or restarts the services to pick up the new configuration:

sail down  # Stops and removes containers
sail up -d # Starts all services in detached mode

This ensures that the newly configured MySQL container is running and accessible on the network when your sail mysql command executes.

Conclusion

Migrating between environments requires shifting your mindset from traditional host-based connections (like Homestead) to service-based, internal Docker networking (Sail). The error you faced was not a failure of the database itself, but a failure in the hostname resolution layer. By consistently using the service name (mysql) as the DB_HOST and ensuring proper container restart procedures, you can seamlessly transition your project and leverage the power and portability that Laravel Sail offers. Happy coding!