We may earn a referral fee at no additional cost to you when you shop through the links on this page.
You try to reach a MySQL database from another server or a client like Workbench, and the connection is refused: ERROR 2003 (HY000): Can't connect to MySQL server. By default MySQL only listens to itself, so remote clients never get in. This DevAnswers guide opens it up correctly across the three layers that block remote access, then shows the safer SSH-tunnel alternative. (Need the server first? See installing MySQL on Ubuntu.)
Step 1: Let MySQL Listen Beyond localhost
The first reason a remote client is refused is bind-address. By default MySQL and MariaDB ship with bind-address = 127.0.0.1, which accepts connections only from the local machine. On Debian and Ubuntu you change this in the server config: /etc/mysql/mysql.conf.d/mysqld.cnf for MySQL, or /etc/mysql/mariadb.conf.d/50-server.cnf for MariaDB.
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Find the bind-address line and change it. Setting it to 0.0.0.0 listens on every IPv4 interface; setting it to a specific address limits the server to that one interface, which is tighter. Prefer a specific private IP when the server has one:
# All interfaces:
bind-address = 0.0.0.0
# Tighter, if you have a private IP:
# bind-address = 10.0.0.5
Save the file, then restart the service so the change takes effect:
sudo systemctl restart mysql
# MariaDB:
# sudo systemctl restart mariadb
Confirm MySQL is now listening on the external interface rather than just loopback:
sudo ss -tlnp | grep 3306
LISTEN 0 151 0.0.0.0:3306 0.0.0.0:* users:(("mysqld",pid=812,fd=22))
Step 2: Create a User That Can Connect Remotely
A MySQL account is not just a username; it is a username plus the host the connection comes from. An account defined as 'devans'@'localhost' can only connect from the server itself, so even with the port open a remote login is rejected. Create the user scoped to the client’s IP where you can, log in as an admin and run:
-- Scope the account to the connecting host where possible
CREATE USER 'devans'@'203.0.113.10' IDENTIFIED BY 'a-long-random-password'; -- replace devans with your app user
GRANT ALL PRIVILEGES ON devans_db.* TO 'devans'@'203.0.113.10';
FLUSH PRIVILEGES;
Use 'devans'@'%' (any host) only when the client IP is not fixed; that account leans entirely on the firewall and a strong password, so create the user with a long random secret (a password generator is ideal for a network-reachable account). FLUSH PRIVILEGES reloads the grant tables so the new access is live immediately. Swap devans_db for your actual database name.
Step 3: Open the Firewall to a Trusted IP
MySQL listens on TCP port 3306, and the OS firewall has to allow it. Do not open that port to the whole internet: a publicly reachable 3306 is a magnet for brute-force and automated exploitation. With UFW (on Debian, sudo apt install ufw first), allow only the client’s address:
sudo ufw allow from 203.0.113.10 to any port 3306
A blanket sudo ufw allow 3306 works but exposes the port to everyone and should be a last resort. One more thing on cloud servers: the provider’s own firewall or security group (DigitalOcean Cloud Firewalls, an AWS security group) sits in front of UFW, so you have to allow 3306 from the trusted IP there as well, or the packets never reach the box. Check the local rule landed:
sudo ufw status
The Safer Way: Don’t Expose 3306 at All
Every step above widens your attack surface. The most secure approach is to not expose MySQL to the network at all: leave bind-address = 127.0.0.1, keep the firewall closed, and reach the database through an SSH tunnel. The tunnel forwards a local port over your existing SSH login, so to MySQL the traffic looks like it came from localhost:
ssh -o ExitOnForwardFailure=yes -L 3307:localhost:3306 user@your-server
Leave that running, then point your client at 127.0.0.1:3307 on your own machine (a local port other than 3306 avoids a clash if your own machine already runs MySQL). Nothing is exposed, the connection is encrypted, and you can connect as an ordinary localhost user with no remote grants at all. Because the tunnel rides your normal SSH login, there is also one less open port and standing password to manage, which is why it is the default many teams settle on for day-to-day database access.
Test the Connection
If you opened the server directly in Steps 1-3, connect from the client over TCP using its IP and the remote user you created:
mysql -h your-server-ip -u devans -p
If you went the SSH-tunnel route instead, you connect to 127.0.0.1:3307 as one of your existing localhost users (the remote-scoped devans account does not apply, since the tunnel makes the traffic look local), exactly as the tunnel section above describes.
If you still get ERROR 2003 (HY000): Can't connect to MySQL server on '...' (111), the client could not reach the server on port 3306, so a network layer is still blocking: re-check bind-address and the firewall rule, including any cloud security group. That is different from ERROR 2002 (the local Unix-socket error) and from an authentication failure once the connection does open. To isolate a network or firewall block, test the port directly first:
nc -zv your-server-ip 3306
Connecting from an application rather than the CLI? The same host, user, and password go straight into your PHP PDO connection string, so once the mysql client connects, the app will too.
On a Windows client without nc, run Test-NetConnection your-server-ip -Port 3306 in PowerShell for the same check. A refused or timed-out port points at bind-address or the firewall; an open port that still fails in mysql points at the user’s host or an access-denied (1045) error instead.
Summary
“Can’t connect remotely” is almost always one of three layers: MySQL bound to localhost, a user without the right host part, or a closed firewall port. Open exactly what you need, scope the user and the firewall rule to specific IPs, and prefer an SSH tunnel so the database is never exposed in the first place. Line those up and the remote client connects, with ERROR 2003 behind you.
I was able to connected to mysql server remotely and then in all of a sudden it stopped working after updates and upgrade. Using this instruction to check the firewall and add rules to firewall helps me back connected again. Thank you very very much
thanks. work for me
Hi there,
thanks a lot for this tuto to solve.
In my case it did not work :/
I have tried many things already
My user has all privileges enabled
SSH is enabled
UFW is installed and running
Ports are set with allow in from anywhere on nginx http, mysql and even server firewall
I have restarted each time after settings actions
mysql.cnfd is also set with bind address 0.0.0.0
I’m not sure so far if there is still one or few things I could do to solve this lool
May I have a few tips or help please?
Again thanks for all
I’m still getting the same error, after # out the bind-address line in every version of mysql.cnf or my.cnf I can find. Confirmed via use status 3306 is set to ALLOW. Kind of perplexed here. I can connect with MySQL workbench from inside my network, but not from outside. Any other thoughts? Using MySql8 and Ubuntu server 20.04.
ufw save me!
Thanks
Awesome! It’s work.
Thank you!
Implemented the above steps and the problem was resolved immediately. Thank you so much for the guidance.
Thanks. Many “How-To’s” on the web don’t mention the default IP binding thing in MySQL.
Thanks for all…
Works Fine!!!
Still get this
Can’t connect to MySQLServer on ip adress(10600)
it’s working now ,thanks your share
muy bueno gracias
¡A ti!