Fix: MySQL ERROR 2002 (HY000): Can't connect to local MySQL server through socket

The Error

You try to connect to MySQL and get:

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

Or one of these variations:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (13)

The (2) at the end means “No such file or directory” — the socket file doesn’t exist. The (13) means “Permission denied” — the socket file exists but your user can’t access it. Both point to the same underlying problem: the MySQL client can’t communicate with the MySQL server through its Unix socket.

Why This Happens

When you connect to MySQL on Linux or macOS without specifying a hostname (e.g., just mysql -u root), the client doesn’t use TCP. Instead, it connects through a Unix domain socket — a special file on disk that allows inter-process communication. This is faster than TCP because it bypasses the network stack entirely.

The socket file is created by the MySQL server when it starts and removed when it stops. Its default location varies by distribution:

  • Debian/Ubuntu: /var/run/mysqld/mysqld.sock
  • RHEL/CentOS/Fedora: /var/lib/mysql/mysql.sock
  • macOS (Homebrew): /tmp/mysql.sock
  • SUSE/OpenSUSE: /var/run/mysql/mysql.sock

ERROR 2002 means either:

  • MySQL isn’t running, so the socket file was never created (or was removed on shutdown).
  • The socket file exists, but the client is looking in the wrong place. The server and client have different ideas about where the socket lives.
  • The socket file or its directory has wrong permissions, so the client can’t access it.
  • The socket file was deleted while MySQL was still running (e.g., by an overly aggressive tmpwatch or systemd-tmpfiles).
  • Something external is blocking access to the socket file (AppArmor, SELinux, or container isolation).

Fix 1: Start the MySQL Service

The most common cause. MySQL isn’t running, so the socket file doesn’t exist.

Linux (systemd):

sudo systemctl start mysql

On RHEL/CentOS/Fedora, the service name is mysqld:

sudo systemctl start mysqld

Check the status:

sudo systemctl status mysql

If it’s not enabled to start on boot:

sudo systemctl enable mysql

Linux (older init systems):

sudo service mysql start

macOS (Homebrew):

brew services start mysql

After starting, verify the socket file was created:

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

Then test the connection:

mysql -u root -p

If the service fails to start, skip ahead to Fix 9 to check the error log.

Fix 2: Fix the Socket Path in my.cnf

The MySQL client and server both read the socket path from configuration files. If they disagree about the path, the server creates the socket in one location while the client looks for it in another.

Find which config files MySQL is reading:

mysql --help | grep -A 1 "Default options"

This shows something like:

Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf

Check the socket path configured for both [mysqld] (server) and [client] (client):

grep -r "socket" /etc/my.cnf /etc/mysql/ 2>/dev/null

Make sure both sections use the same path. Edit your my.cnf:

[mysqld]
socket=/var/run/mysqld/mysqld.sock

[client]
socket=/var/run/mysqld/mysqld.sock

If you just want to connect right now without changing the config, pass the socket path directly:

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

To find where the running MySQL server actually created the socket:

sudo find / -name "mysql*.sock" -type s 2>/dev/null

Restart MySQL after changing the config:

sudo systemctl restart mysql

Fix 3: Recreate the Socket Directory

On some systems, the socket directory (e.g., /var/run/mysqld/) doesn’t survive a reboot because /var/run is mounted as a tmpfs. If the directory is missing, MySQL can’t create the socket file and fails to start.

Check if the directory exists:

ls -la /var/run/mysqld/

If it doesn’t exist, create it with the correct ownership:

sudo mkdir -p /var/run/mysqld
sudo chown mysql:mysql /var/run/mysqld
sudo chmod 755 /var/run/mysqld

Then restart MySQL:

sudo systemctl restart mysql

To make this permanent across reboots, create a tmpfiles.d configuration:

echo "d /var/run/mysqld 0755 mysql mysql -" | sudo tee /etc/tmpfiles.d/mysql.conf

Fix 4: Fix Permissions on the Socket File

If the error ends with (13) instead of (2), the socket file exists but your user can’t access it. This is a permissions problem, similar to file and socket permission issues in Docker.

Check the socket file permissions:

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

The socket should be owned by the mysql user and be readable/writable by others:

srwxrwxrwx 1 mysql mysql 0 Apr 17 10:00 /var/run/mysqld/mysqld.sock

If the permissions are too restrictive, fix them:

sudo chmod 777 /var/run/mysqld/mysqld.sock

Also check the directory permissions. The user running the MySQL client needs execute permission on every directory in the path:

sudo chmod 755 /var/run/mysqld

If the permissions keep resetting, check the my.cnf for a restrictive socket permission setting or examine whether AppArmor/SELinux is interfering (see Fix 7).

Fix 5: Connect via TCP Instead of the Socket

If you need to connect immediately and can’t fix the socket issue right away, bypass the socket entirely by forcing a TCP connection:

mysql -u root -p --protocol=tcp

Or use 127.0.0.1 instead of localhost. When you use localhost, MySQL uses the Unix socket. When you use 127.0.0.1, it uses TCP:

mysql -u root -p -h 127.0.0.1

For application connection strings, use 127.0.0.1 instead of localhost:

mysql://root:password@127.0.0.1:3306/mydb

In PHP (php.ini or your app config):

mysqli.default_host = 127.0.0.1

This is a valid workaround, but it’s slightly slower than socket connections for local access. For remote connections, TCP is the only option anyway. Make sure MySQL is listening on TCP by checking:

sudo ss -tlnp | grep 3306

If nothing shows up, ensure skip-networking is not enabled in my.cnf:

# Remove or comment out this line:
# skip-networking

Fix 6: Fix a Deleted Socket File (Without Restarting)

If something deleted the socket file while MySQL is still running (for example, tmpwatch or systemd-tmpfiles cleaning up /tmp or /var/run), MySQL is running but unreachable.

Check if MySQL is actually running:

ps aux | grep mysqld

If it is running, the quickest fix is to restart MySQL so it recreates the socket:

sudo systemctl restart mysql

To prevent tmpwatch or systemd-tmpfiles from cleaning up the socket in the future, exclude the directory. For systemd-tmpfiles, create a configuration:

echo "x /var/run/mysqld/*" | sudo tee /etc/tmpfiles.d/mysql-protect.conf

For tmpwatch on RHEL/CentOS, edit /etc/cron.daily/tmpwatch and add an exclusion for the socket directory.

Fix 7: AppArmor or SELinux Blocking Access

Security frameworks like AppArmor (Ubuntu/Debian) and SELinux (RHEL/CentOS/Fedora) can silently block MySQL from creating or accessing the socket file.

SELinux:

Check if SELinux is blocking MySQL:

sudo ausearch -m AVC -ts recent | grep mysql

Or check the audit log:

sudo grep mysql /var/log/audit/audit.log | tail -20

Temporarily set SELinux to permissive to test:

sudo setenforce 0
sudo systemctl restart mysql

If MySQL works in permissive mode, generate a proper SELinux policy:

sudo ausearch -c 'mysqld' --raw | audit2allow -M mysql_local
sudo semodule -i mysql_local.pp

Then re-enable enforcing mode:

sudo setenforce 1

AppArmor:

Check if AppArmor is restricting MySQL:

sudo aa-status | grep mysql

If the MySQL profile is in enforce mode, temporarily switch it to complain mode:

sudo aa-complain /usr/sbin/mysqld
sudo systemctl restart mysql

If that fixes it, update the AppArmor profile to allow the socket path and then re-enforce:

sudo aa-enforce /usr/sbin/mysqld

Fix 8: Docker MySQL Socket Issues

When running MySQL in a Docker container, the socket file exists inside the container, not on the host. A client running on the host can’t access it.

Connect to Docker MySQL via TCP:

mysql -u root -p -h 127.0.0.1 -P 3306

Make sure you exposed the port in your docker run command:

docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=secret mysql:8

Share the socket file with the host:

Mount a volume for the socket:

docker run -d --name mysql \
  -v /var/run/mysqld:/var/run/mysqld \
  -e MYSQL_ROOT_PASSWORD=secret \
  mysql:8

Connecting from another container (docker-compose):

Use the service name as the hostname, just as you would with PostgreSQL container networking:

services:
  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: secret
    ports:
      - "3306:3306"

  app:
    build: .
    environment:
      DATABASE_URL: mysql://root:secret@db:3306/mydb
    depends_on:
      - db

The hostname inside the container is db, not localhost.

Fix 9: MySQL Crashed — Check the Error Log

If MySQL was running and suddenly stopped, the socket file disappears and you get ERROR 2002. Check the error log to find out why it crashed:

# Debian/Ubuntu
sudo tail -100 /var/log/mysql/error.log

# RHEL/CentOS/Fedora
sudo tail -100 /var/log/mysqld.log

# Or use journalctl
sudo journalctl -u mysql --no-pager -n 100

Common crash causes:

  • Disk full. MySQL can’t write and shuts down. Free up space:
df -h
  • Out of memory. The OOM killer terminated MySQL. Check:
sudo dmesg | grep -i "oom" | grep mysql

Reduce MySQL memory usage in my.cnf:

[mysqld]
innodb_buffer_pool_size = 256M
key_buffer_size = 32M
  • Corrupted InnoDB tablespace. Look for InnoDB: corruption messages in the error log. Start MySQL in recovery mode:
[mysqld]
innodb_force_recovery = 1

Start with 1 and increase up to 6 if needed. Dump your data and rebuild once it starts.

  • Stale PID file. If MySQL didn’t shut down cleanly, a PID file may prevent it from starting:
sudo rm /var/run/mysqld/mysqld.pid
sudo systemctl start mysql

Only remove the PID file if you’ve confirmed MySQL is not running with ps aux | grep mysqld.

Fix 10: tmpdir Full or Unwritable

MySQL uses a temporary directory for sorting, temporary tables, and other operations. If this directory is full or unwritable, MySQL may fail to start.

Check the configured tmpdir:

mysql -u root -p -e "SHOW VARIABLES LIKE 'tmpdir';"

If you can’t connect, check the config:

grep tmpdir /etc/mysql/my.cnf /etc/my.cnf 2>/dev/null

Check if the tmpdir has space and correct permissions:

df -h /tmp
ls -la /tmp

If /tmp is full, clean it up or point MySQL to a different directory:

[mysqld]
tmpdir = /var/tmp

Restart MySQL after changing this.

Fix 11: Multiple MySQL Installations Conflicting

Having multiple MySQL installations (or MySQL alongside MariaDB) can cause socket conflicts. Each instance may try to use a different socket path, or one installation’s client may try to connect to another installation’s server.

Check for multiple installations:

# Debian/Ubuntu
dpkg -l | grep -i mysql
dpkg -l | grep -i mariadb

# RHEL/CentOS
rpm -qa | grep -i mysql
rpm -qa | grep -i mariadb

Check for multiple running instances:

ps aux | grep mysqld

If multiple instances are running, each should have a unique socket path, port, and data directory in its my.cnf. To connect to a specific instance, use its socket:

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

If you only need one installation, remove the conflicting one. On Debian/Ubuntu, MariaDB and MySQL use the same socket path by default, so they can’t run simultaneously without reconfiguration.

Fix 12: macOS Homebrew-Specific Issues

On macOS with Homebrew, MySQL uses /tmp/mysql.sock by default, but several things can go wrong.

Check if MySQL is running:

brew services list | grep mysql

Start MySQL:

brew services start mysql

Check where the socket actually is:

ls -la /tmp/mysql.sock

If the socket is missing but MySQL is running, check if Homebrew installed MySQL with a custom socket path:

cat /opt/homebrew/etc/my.cnf 2>/dev/null
cat /usr/local/etc/my.cnf 2>/dev/null

Common macOS fix — create a symlink:

If your client expects the socket at /tmp/mysql.sock but MySQL creates it elsewhere:

sudo ln -s /opt/homebrew/var/mysql/mysqld.local.sock /tmp/mysql.sock

Fix for macOS Sequoia and later:

Recent macOS versions may clean up /tmp more aggressively. If the socket keeps disappearing, configure MySQL to use a different directory:

[mysqld]
socket=/opt/homebrew/var/mysql/mysqld.sock

[client]
socket=/opt/homebrew/var/mysql/mysqld.sock

If you previously installed MySQL via the official DMG and now use Homebrew (or vice versa), conflicting configurations may exist. Check for config files in multiple locations:

ls -la /etc/my.cnf /usr/local/etc/my.cnf /opt/homebrew/etc/my.cnf ~/.my.cnf 2>/dev/null

Fix 13: WSL (Windows Subsystem for Linux) Specific Issues

Running MySQL inside WSL has unique challenges because WSL doesn’t use systemd by default (WSL 1 and older WSL 2).

Start MySQL manually on WSL without systemd:

sudo service mysql start

Or start the daemon directly:

sudo mysqld_safe &

Check if MySQL is running:

ps aux | grep mysqld

Socket path issues on WSL:

The socket directory may not exist after a WSL restart. Create it:

sudo mkdir -p /var/run/mysqld
sudo chown mysql:mysql /var/run/mysqld
sudo service mysql start

WSL 2 with systemd enabled:

If you’ve enabled systemd in WSL 2 (via /etc/wsl.conf), the standard systemctl commands work:

sudo systemctl start mysql

Connecting from Windows to MySQL inside WSL:

From Windows, connect via TCP to WSL’s IP address:

mysql -u root -p -h 127.0.0.1 -P 3306

The socket file is not accessible from Windows because it’s inside the WSL filesystem. Always use TCP for cross-system connections.

Connecting from WSL to MySQL on Windows:

If MySQL is installed on Windows (not WSL), connect via TCP using the Windows host IP:

mysql -u root -p -h $(hostname).local -P 3306

Still Not Working?

MySQL starts but the socket disappears after a few seconds

This usually means MySQL starts, encounters an error, and shuts down immediately. The socket exists briefly but is removed on shutdown. Check the error log — the real error is there:

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

Common causes: wrong file ownership on the data directory, InnoDB log file size mismatch after a configuration change, or insufficient file descriptors.

Connection works as root but not as your user

If sudo mysql -u root works but mysql -u root doesn’t, the issue is file permissions on the socket or its parent directory. Your regular user needs read and execute access to /var/run/mysqld/. This is similar to other permission-denied issues in Bash where the current user lacks the necessary access rights.

ERROR 1045 instead of ERROR 2002

If you’ve fixed the socket issue but now see ERROR 1045 (28000): Access denied for user, that’s a separate authentication problem. The connection itself is working — your credentials are wrong. See Fix: MySQL Access Denied for User for solutions.

The socket file exists but connections still fail

If the socket file is present and has correct permissions but connections still fail, the file may be stale (left over from a crashed MySQL instance). Remove it and restart:

sudo rm /var/run/mysqld/mysqld.sock
sudo systemctl restart mysql

Application-specific connection issues

Some applications have their own MySQL socket configuration separate from the system default:

  • PHP: Check pdo_mysql.default_socket and mysqli.default_socket in php.ini.
  • Python (mysqlclient): Pass unix_socket in your connect call or set it in a my.cnf that your app reads.
  • Ruby on Rails: Set socket in config/database.yml.
  • WordPress: Set DB_HOST in wp-config.php to localhost:/var/run/mysqld/mysqld.sock.

Nothing works and you need to connect to a remote database

If you’re actually trying to reach a MySQL server on another machine, the socket approach won’t work at all. Use TCP with the remote host’s IP or hostname:

mysql -u root -p -h 192.168.1.100 -P 3306

Make sure the remote server’s bind-address in my.cnf allows connections from your IP, and that the firewall permits traffic on port 3306. This is conceptually the same as troubleshooting remote connection issues with MongoDB or Redis — verify the service is listening, the bind address is correct, and the firewall is open.


Related: If you’re troubleshooting other database connection problems, see Fix: PostgreSQL Connection Refused and Fix: MySQL Access Denied for User. For Docker socket and permission issues, see Fix: Docker Permission Denied. If your connection string is coming from environment variables that aren’t loading, see Fix: Bash Permission Denied.

Related Articles