How to Fix MySQL "Connection Refused" Error on Linux — 5 Checkpoints That Solve Every Case

By Adhen Prasetiyo

Monday, March 9, 2026 • 7 min read

Linux terminal showing MySQL connection refused error message

Your application crashes. The logs show one line that makes your stomach drop:

ERROR 2003 (HY000): Can’t connect to MySQL server on ‘localhost’ (111 “Connection refused”)

Or maybe it’s this one:

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)

Either way, your database is unreachable and everything that depends on it — your website, your API, your application — is dead in the water.

Before you start searching through Stack Overflow threads and changing random configuration values, stop. There are exactly five things that cause MySQL connection failures on Linux. Check them in order and you’ll find the problem in minutes.

The 5 Checkpoints

Here’s the systematic approach. Every MySQL “Connection refused” error is caused by one of these five things:

  1. MySQL isn’t running
  2. MySQL isn’t listening on the right port or interface
  3. A firewall is blocking the connection
  4. The MySQL user doesn’t have permission to connect from your location
  5. The socket file is missing or misconfigured (local connections only)

Let’s check each one.

Checkpoint 1: Is MySQL Actually Running?

This sounds obvious, but you’d be surprised how often MySQL has silently crashed or failed to start after a reboot.

sudo systemctl status mysql

On some distributions (CentOS, RHEL, Fedora), the service is called mysqld instead:

sudo systemctl status mysqld

You’re looking for “active (running)” in the output. If it says “inactive (dead)” or “failed”, MySQL isn’t running.

Start it:

sudo systemctl start mysql

If it fails to start, check the error log:

sudo journalctl -u mysql -e

Or check the MySQL error log directly:

sudo tail -50 /var/log/mysql/error.log

Common reasons MySQL fails to start:

Disk space is full. MySQL needs space to write data files, logs, and temporary tables. Check with df -h. If your disk is at 100%, free up space before trying to start MySQL.

Another process is using port 3306. Check with sudo ss -tlnp | grep 3306. If another MySQL instance or MariaDB is already running on that port, you need to stop it first.

Corrupted InnoDB files. If MySQL crashes during a write operation, InnoDB data files can become corrupted. The error log will mention “InnoDB: Unable to lock” or “table is marked as crashed.” This requires database repair — a topic for a separate guide.

Wrong permissions on data directory. MySQL’s data directory (usually /var/lib/mysql) must be owned by the mysql user. Check with ls -la /var/lib/mysql. Fix with sudo chown -R mysql:mysql /var/lib/mysql.

Once MySQL is running, move to the next checkpoint.

Checkpoint 2: Is MySQL Listening on the Right Port and Interface?

MySQL is running, but is it actually accepting connections? Check:

sudo ss -tlnp | grep 3306

You should see something like:

LISTEN  0  151  127.0.0.1:3306  0.0.0.0:*  users:(("mysqld",pid=1234,fd=22))

Pay attention to the IP address before :3306:

127.0.0.1:3306 — MySQL only accepts connections from localhost. Remote connections will be refused.

0.0.0.0:3306 — MySQL accepts connections from any IP address. Both local and remote connections work.

If you need remote connections, edit the MySQL configuration:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

On CentOS/RHEL, the file might be at /etc/my.cnf or /etc/mysql/my.cnf.

Find the bind-address line and change it:

# Only local connections (default)

bind-address = 127.0.0.1

# Accept connections from any IP

bind-address = 0.0.0.0

Save and restart MySQL:

sudo systemctl restart mysql

Important security note: Setting bind-address to 0.0.0.0 makes MySQL accessible from the internet if your server has a public IP. Always combine this with proper firewall rules and strong MySQL user passwords. Never expose MySQL to the public internet without additional security measures.

Checkpoint 3: Is a Firewall Blocking the Connection?

MySQL is running and listening, but connections from other machines are refused. The firewall is the likely culprit.

Ubuntu/Debian (UFW):

sudo ufw status

If the firewall is active and port 3306 isn’t listed, add it:

sudo ufw allow 3306/tcp

For more security, allow only specific IPs:

sudo ufw allow from 192.168.1.100 to any port 3306

CentOS/RHEL (firewalld):

sudo firewall-cmd --list-ports

If 3306 isn’t listed:

sudo firewall-cmd --permanent --add-port=3306/tcp

sudo firewall-cmd --reload

Check iptables directly (works on all distributions):

sudo iptables -L -n | grep 3306

If there’s a DROP or REJECT rule for port 3306, that’s your problem. Remove it or add an ACCEPT rule above it.

Cloud server providers (AWS, DigitalOcean, Google Cloud, etc.) have their own firewall rules separate from the OS firewall. Check your cloud provider’s security groups or firewall settings and make sure port 3306 is allowed.

Checkpoint 4: Does the MySQL User Have Permission to Connect?

MySQL has its own user permission system that’s independent of Linux users. A MySQL user can exist but still be restricted to connecting only from specific hosts.

Connect to MySQL locally (this usually works even when remote connections fail):

sudo mysql -u root

Or if root requires a password:

mysql -u root -p

Check existing users and their host permissions:

SELECT Host, User FROM mysql.user;

The output looks like:

+-----------+------------------+

| Host      | User             |

+-----------+------------------+

| localhost | root             |
| localhost | mysql.sys        |
| localhost | debian-sys-maint |

+-----------+------------------+

See the problem? All users have localhost as their host. No user can connect from a remote machine.

Create a user for remote access:

CREATE USER 'myapp'@'%' IDENTIFIED BY 'strong_password_here';

GRANT ALL PRIVILEGES ON myappdb.* TO 'myapp'@'%';

FLUSH PRIVILEGES;

The % wildcard means “any host.” For better security, specify the exact IP:

CREATE USER 'myapp'@'192.168.1.100' IDENTIFIED BY 'strong_password_here';

GRANT ALL PRIVILEGES ON myappdb.* TO 'myapp'@'192.168.1.100';

FLUSH PRIVILEGES;

MariaDB 10.4+ note: MariaDB versions 10.4 and later use the unix_socket authentication plugin by default for the root user. This means you can only log in as root if your Linux user is also root. If you’re getting “Access denied” when trying mysql -u root -p, try sudo mysql instead — it authenticates using your OS identity.

Checkpoint 5: Is the Socket File Missing? (Local Connections Only)

If you’re connecting locally and getting:

ERROR 2002: Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)

The socket file is missing. This happens when MySQL crashes or isn’t started properly.

Check if the socket file exists:

ls -la /var/run/mysqld/mysqld.sock

If it doesn’t exist, restart MySQL — it creates the socket file on startup:

sudo systemctl restart mysql

If the file still doesn’t appear, check that the socket directory exists and has the right permissions:

sudo mkdir -p /var/run/mysqld

sudo chown mysql:mysql /var/run/mysqld

sudo systemctl restart mysql

Socket path mismatch: Sometimes the MySQL server creates the socket in one location but the client looks for it in another. Check where the server puts it:

sudo grep socket /etc/mysql/mysql.conf.d/mysqld.cnf

And where the client expects it:

mysql --print-defaults | grep socket

If they don’t match, either update the configuration or specify the socket path when connecting:

mysql -u root --socket=/var/run/mysqld/mysqld.sock

The Docker Connection Problem

If your application runs in Docker and MySQL runs on the host (or vice versa), “Connection refused” is almost guaranteed on your first attempt. Docker containers have their own network namespace — localhost inside a container refers to the container itself, not the host machine.

App in Docker, MySQL on host:

Don’t use localhost or 127.0.0.1 as the MySQL host in your app config. Instead:

On Mac/Windows: use host.docker.internal as the MySQL host.

On Linux: use the Docker bridge IP, typically 172.17.0.1. Find it with:

ip addr show docker0

Also make sure MySQL’s bind-address is 0.0.0.0 (not 127.0.0.1) so it accepts connections from the Docker network.

Both in Docker (docker-compose):

Use the service name as the hostname. In your docker-compose.yml:

services:

  app:

    # your app config

    environment:

      DB_HOST: db

  db:

    image: mysql:8.0

    # your MySQL config

The hostname db automatically resolves to the MySQL container’s IP within the Docker network.

Quick Diagnostic Cheat Sheet

Run these commands in order to diagnose the problem in under 60 seconds:

# 1. Is MySQL running?

sudo systemctl status mysql

# 2. Is it listening?

sudo ss -tlnp | grep 3306

# 3. Is the firewall blocking?

sudo ufw status  # Ubuntu/Debian

sudo firewall-cmd --list-ports  # CentOS/RHEL

# 4. Can you connect locally?

sudo mysql -u root

# 5. Does the socket exist?

ls -la /var/run/mysqld/mysqld.sock

Within these five commands, you’ll know exactly where the problem is. Fix that one thing, and your connection works.

Step-by-Step Guide

1

Check if MySQL is actually running

Open a terminal and run sudo systemctl status mysql or sudo systemctl status mysqld depending on your Linux distribution. If the status shows inactive or dead MySQL is not running. Start it with sudo systemctl start mysql. If it fails to start check the error log with sudo journalctl -u mysql -e to see what went wrong. Common startup failures include corrupted data files insufficient disk space or port conflicts with another service.

2

Verify MySQL is listening on the correct port

Run sudo ss -tlnp | grep 3306 to check if MySQL is listening on port 3306. If there is no output MySQL is either not running or configured to listen on a different port. Check the MySQL configuration file at /etc/mysql/mysql.conf.d/mysqld.cnf or /etc/my.cnf and look for the port setting. Also check the bind-address setting which controls which IP addresses MySQL accepts connections from. If bind-address is set to 127.0.0.1 MySQL only accepts local connections. Change it to 0.0.0.0 to accept connections from any IP then restart MySQL.

3

Check firewall rules

If MySQL is running and listening but remote connections are refused the firewall may be blocking port 3306. On Ubuntu or Debian run sudo ufw status to check. If the firewall is active allow MySQL with sudo ufw allow 3306/tcp. On CentOS or RHEL run sudo firewall-cmd --list-ports to check and sudo firewall-cmd --permanent --add-port=3306/tcp then sudo firewall-cmd --reload to allow MySQL traffic.

4

Fix MySQL user permissions for remote access

Connect to MySQL locally with sudo mysql -u root and run SELECT Host, User FROM mysql.user to see which users exist and what hosts they can connect from. If a user only has localhost as the host they cannot connect remotely. Create a user for remote access with CREATE USER 'username'@'%' IDENTIFIED BY 'password' then GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'%' then FLUSH PRIVILEGES. The percent symbol means the user can connect from any IP address.

5

Fix socket file issues for local connections

If you get the error Can't connect to local MySQL server through socket the socket file is missing or in the wrong location. Check where MySQL expects the socket file by running mysql --print-defaults and looking for the socket path. Then check if the file exists with ls -la /var/run/mysqld/mysqld.sock. If the file is missing MySQL probably crashed or was not started properly. Restart MySQL with sudo systemctl restart mysql and the socket file will be recreated automatically.

Frequently Asked Questions

What is the difference between MySQL error 2002 and error 2003?
Error 2002 means the MySQL client cannot find the local socket file to connect. This happens when MySQL is not running or the socket file path is misconfigured. The fix is to start MySQL or correct the socket path in the configuration. Error 2003 means the connection was actively refused over the network. This happens when MySQL is not listening on the expected port the firewall is blocking the port or bind-address is restricting connections. The fix depends on which of these causes applies.
How do I connect to MySQL from a Docker container?
If MySQL runs on the host machine and your app runs in a Docker container use host.docker.internal as the hostname on Mac and Windows. On Linux use the host network IP typically 172.17.0.1 for the default Docker bridge network. Also make sure MySQL bind-address is set to 0.0.0.0 not 127.0.0.1 and that the MySQL user has permission to connect from the Docker network IP range.
How do I reset the MySQL root password on Linux?
Stop MySQL with sudo systemctl stop mysql. Start it in safe mode with sudo mysqld_safe --skip-grant-tables and open a new terminal. Connect with sudo mysql -u root and run ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password' then FLUSH PRIVILEGES. Stop the safe mode process and restart MySQL normally with sudo systemctl start mysql. You can now log in with the new password.
Why does MySQL connection work locally but not remotely?
Three things cause this. First bind-address in the MySQL configuration is set to 127.0.0.1 which means MySQL only accepts local connections. Change it to 0.0.0.0 and restart. Second the firewall is blocking port 3306 from external traffic. Open the port with ufw or firewall-cmd. Third the MySQL user account only has localhost permission. Create a user with the percent wildcard host to allow remote connections.
Adhen Prasetiyo

Research Bug bounty at javahack team

Research Bug bounty Profesional

Web Development Research Bug Hunter
View all articles →