MySQL "ERROR 2003: Can't connect to MySQL server": read the number in brackets
Fix MySQL ERROR 2003 "Can't connect to MySQL server": the number in brackets says if it's a stopped server, bind-address, a firewall or the wrong host in Docker.
by OhSudo ··
Not sure this is your cause?Find it step by step: Can't connect to the database →
ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.5:3306' (111)Your client tried to open a TCP connection and failed, so MySQL hasn’t checked a user or a password yet. The number in brackets at the end is the operating system’s reason, and it decides where to look:
| Code | Means | Likely cause |
|---|---|---|
111 (Linux), 61 (macOS), 10061 (Windows) |
Connection refused | Nothing is listening there: it’s stopped, or bind-address keeps it on localhost |
110 (Linux), 60 (macOS), 10060 (Windows) |
Timed out | A firewall drops the packets, or the address is wrong |
113 |
No route to host | A network problem, or a firewall rejecting it |
- Clientconnects to 10.0.0.5:3306TCP
- Firewalldrops it: timed out (110)passes, or not(fails)
- mysqldstopped, or bind-address on localhost: refused (111)(breaks here)
TL;DR
On the database server:
sudo systemctl status mysql # mysqld or mariadb on RHELsudo ss -tlnp | grep 3306 # is it listening, and on which address?127.0.0.1:3306 means it only accepts local connections: change bind-address (section 2). 0.0.0.0:3306 with a timeout from elsewhere means a firewall (section 3).
1. Is the server running?
sudo systemctl status mysqlsudo journalctl -u mysql -n 30 --no-pagerThe service is mysql on Ubuntu and Debian, mysqld on RHEL, and often mariadb. If it’s stopped, start it and read why it stopped: a full disk is a usual reason, and no space left on device covers that.
On Windows:
Get-Service *mysql*, *maria*Test-NetConnection 10.0.0.5 -Port 33062. Refused: bind-address
Check the address it listens on:
sudo ss -tlnp | grep 3306LISTEN 0 151 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=812,fd=23))127.0.0.1 is the default on Debian and Ubuntu, so connections from other machines are refused. Set the address in the config file:
/etc/mysql/mysql.conf.d/mysqld.cnfon Ubuntu and Debian;/etc/mysql/mariadb.conf.d/50-server.cnffor MariaDB there;/etc/my.cnfor/etc/my.cnf.d/on RHEL.
[mysqld]bind-address = 10.0.0.5Use the machine’s private address, or 0.0.0.0 for all of them. Then restart and check again:
sudo systemctl restart mysqlsudo ss -tlnp | grep 3306If ss shows nothing while the service runs, look for skip_networking in the config: it turns off TCP completely. If the port isn’t 3306, a port setting has changed it:
mysql -e "SHOW VARIABLES WHERE Variable_name IN ('port','bind_address','skip_networking');"3. Timed out: the firewall
Here the packets get dropped on the way. Test from the client, without MySQL involved:
nc -vz -w 5 10.0.0.5 3306On the server, open the port only for the machines that need it:
# Ubuntu / Debiansudo ufw allow from 10.0.0.20 to any port 3306 proto tcp
# RHEL / Rocky / AlmaLinuxsudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.20" port port="3306" protocol="tcp" accept'sudo firewall-cmd --reloadIn the cloud, also check the security group or network firewall. They sit outside the machine, so the server never sees those packets. You can practice the difference between the two failures in the terminal, and “Connection timed out” vs “Connection refused” explains it in depth.
Warning
Don’t open 3306 to the whole internet. Bots scan for it around the clock. Use a private network, a VPN or an SSH tunnel: ssh -L 3306:127.0.0.1:3306 me@10.0.0.5, then connect to 127.0.0.1 on your machine. The Port Lookup lists what else shouldn’t be public.
4. Docker
Inside a container, 127.0.0.1 is the container itself. That’s the classic reason for error 111 in a Compose project. Use the service’s name:
services: app: environment: DB_HOST: db # not localhost db: image: mysql:8.4Connecting from your computer instead? The port has to be published, with ports: ["127.0.0.1:3306:3306"]. A database also takes a while to start, so an app that connects right away fails once and then works: add a healthcheck. Connecting to localhost from a container goes through every combination.
5. It connects now: what’s next
Past this error, you might see the next layer:
ERROR 1130 (HY000): Host '10.0.0.20' is not allowed to connect to this MySQL serverERROR 1045 (28000): Access denied for user 'app'@'10.0.0.20' (using password: YES)Good news: the network works. Those are about accounts, and an account in MySQL is a user and a host. See MySQL error 1045.
Shell, we have a problem!
Similar, but different: ERROR 2002: Can't connect to local MySQL server through socket is the local connection, without TCP: see the socket article. ERROR 2005: Unknown MySQL server host means the name doesn’t resolve. ERROR 2013: Lost connection to MySQL server means it connected and then dropped. ERROR 1040: Too many connections means the server is reachable and full: see MySQL error 1040. ERROR 1130: Host is not allowed to connect means you reached it, and no account matches your address: see MySQL error 1130. An import that stops with Got a packet bigger than 'max_allowed_packet' bytes connected fine, and sent too much at once.
Found this useful? Share it.
Found a mistake? Let us know at contact@ohsudo.com.