MySQL connection failures in Docker on Ubuntu 22.04 typically stem from incorrect port mappings, restrictive firewall rules, or improper network configuration between the host and container. Resolving this requires verifying that the MySQL port is correctly exposed, ensuring the database user allows remote connections, and checking that the application connects via localhost or the correct container IP address rather than an unreachable external interface.
Verifying Port Mapping and Network Configuration
The most common reason a MySQL server inside a Docker container appears unreachable is an incorrect port mapping during container creation. When you start a MySQL container, you must explicitly map the internal port to an external port using the-p flag. If you omit this flag or map it incorrectly, the host machine cannot reach the service running inside the container.
For example, a standard command should look like this:
docker run --name mysql-db -e MYSQL_ROOT_PASSWORD=secret -p 3306:3306 -d mysql:latest
In this command, the first 3306 represents the port on your Ubuntu host, and the second 3306 is the port inside the container where MySQL listens. If you mapped it to -p 3307:3306, you must connect to port 3307 on the host. Always verify the running container’s ports using docker ps. This command lists all active containers and their assigned port bindings. If the output shows no port mapping for the MySQL container, the service is isolated from the network stack of the host.
Additionally, ensure that the container is using the default bridge network or a custom user-defined network. Containers on the default bridge network can communicate with each other using IP addresses, but they are not reachable by name. For more robust connectivity, especially if you are running multiple services, create a custom network:
docker network create my-net
docker run --network my-net ...
This setup allows containers to resolve each other by name, reducing reliance on dynamic IP addresses which change upon restart.
Configuring MySQL User Permissions
Even if the network path is clear, MySQL will reject connections if the user account does not permit access from the connecting host. By default, MySQL creates users that may only allow local connections (localhost). To connect from a Docker container or another host, you must grant permissions for the specific user to connect from any host or the specific IP range. Log into the MySQL shell within the container:docker exec -it mysql-db mysql -u root -p
Once inside, check the existing users and their hosts:
SELECT user, host FROM mysql.user;
If you see a user with host set to localhost, it cannot be accessed remotely. You need to create a new user or modify the existing one to allow connections from % (any host) or the specific subnet. Execute the following SQL commands to grant access:
CREATE USER 'myuser'@'%' IDENTIFIED BY 'mypassword';
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Using % is convenient for development but poses security risks in production. In a production environment, restrict the host to the specific IP of the application server or the Docker network subnet. Remember that changing user permissions requires flushing privileges to apply changes immediately without restarting the database engine.
Checking Ubuntu Firewall Rules
Ubuntu 22.04 usesufw (Uncomplicated Firewall) by default. If the firewall is enabled, it may block incoming connections on port 3306, preventing external tools or other containers from reaching the MySQL instance. Check the status of the firewall using:
sudo ufw status
If the status is active, look for rules allowing traffic on port 3306. If no such rule exists, add it carefully. Allowing unrestricted access to MySQL ports is dangerous. Instead, allow traffic only from trusted sources:
sudo ufw allow from 192.168.1.0/24 to any port 3306
Replace the IP range with your actual network subnet. If you are connecting from the same host where Docker is running, note that Docker handles its own iptables rules. However, if you are trying to connect from another machine on the same LAN, the host firewall must permit the traffic. Disabling the firewall entirely (sudo ufw disable) is not recommended for security reasons but can help isolate whether the firewall is the culprit during troubleshooting.
DNS and Host Resolution Issues
Applications often fail to connect because they attempt to resolvelocalhost or 127.0.0.1 instead of the container’s network address. Inside the container, localhost refers to the container itself. If your application runs outside the container, it must use the host’s IP address or the container’s name if connected to the same Docker network.
If you are experiencing intermittent connection drops, consider using a static IP for the container or relying on Docker DNS. Docker provides an internal DNS server that resolves container names to their current IP addresses. Ensure your application configuration points to the container name (e.g., mysql-db) rather than a hardcoded IP, unless you have implemented a static IP assignment strategy.
For deeper diagnostics, use telnet or nc (netcat) from the host to test connectivity:
nc -zv 127.0.0.1 3306
A successful connection returns a confirmation message, while a failure indicates a network or permission block. This simple test helps distinguish between MySQL configuration errors and underlying network issues.
Related Troubleshooting Steps
Sometimes the issue lies not with MySQL itself but with the Docker environment or the operating system’s handling of virtual networks. If you are running Ubuntu under WSL2, as discussed in Troubleshooting Docker on Ubuntu under WSL2 with Docker Desktop, network interfaces behave differently. WSL2 uses a virtual switch, which can complicate direct port forwarding from the Windows host to the Linux container. In such cases, you may need to configure port forwarding rules explicitly in Windows or adjust the Docker daemon settings to bind to0.0.0.0 instead of 127.0.0.1.
Another potential pitfall involves file permissions and storage drivers. While less common for connection issues, misconfigured volume mounts can prevent MySQL from starting properly, leading to a non-responsive state. If the container exits immediately after starting, check the logs with docker logs mysql-db. Errors related to data directory permissions or corrupted system tables will appear here. Addressing these startup failures is a prerequisite for establishing any connection.
Frequently Asked Questions
Why can I ping the container IP but not connect to port 3306?
Pinging confirms basic network layer connectivity, but TCP port 3306 might still be blocked by a firewall or not listened on by MySQL. Verify that MySQL is actively listening on the port using netstat or ss inside the container, and ensure no UFW or iptables rules are dropping packets on that specific port.
How do I reset the MySQL root password if I am locked out?
You can bypass authentication by starting the MySQL container with the --skip-grant-tables flag. This allows you to log in without a password, update the user credentials in the mysql.user table, and then restart the container normally without the flag to restore security checks.
Is it safe to allow MySQL connections from any host (%)?
Allowing connections from % is convenient for development but exposes your database to potential brute-force attacks from any IP address. In production, always restrict access to specific IPs or subnets known to host your application servers to minimize the attack surface.
What happens if I change the port mapping after the container is created?
Port mappings defined at creation time cannot be changed without recreating the container. You must stop and remove the old container, then start a new one with the desired -p flags. Be sure to attach the same volume mounts to preserve your data during this process.
Can I connect to MySQL using IPv6 addresses?
Yes, but both Docker and MySQL must be configured to support IPv6. Ensure your Docker network supports IPv6 and that your MySQL user grants permissions for IPv6 addresses (e.g., 'user'@'::1' or 'user'@'::%'). Default configurations often prioritize IPv4, which may cause resolution issues if your client attempts IPv6 first.