/인프라/ERROR 2002 (HY000) MySQL Socket Connection Failure: A Cause-by-Cause Fix Guide
InfrastructureMySQL ERROR 2002MySQL 소켓 연결 실패

ERROR 2002 (HY000) MySQL Socket Connection Failure: A Cause-by-Cause Fix Guide

Diagnose ERROR 2002 (HY000) Can't connect to local MySQL server through socket by errno (2)/(13) and six root causes. Recover in five minutes with copy-paste systemctl/ss commands, socket path and permission fixes, and a TCP fallback.

ERROR 2002 (HY000) MySQL Socket Connection Failure: A Cause-by-Cause Fix Guide

ERROR 2002 (HY000) MySQL Socket Connection Failure: A 5-Minute Cause-by-Cause Fix Guide

You're mid-deploy—or you just got paged at 3 a.m.—and this one line shows up. Your blood runs cold.

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

This is a hands-on playbook: copy-paste the commands from the top down, no guessing, and you'll isolate the cause and recover in five minutes. We skip ERROR 1045 (auth), 1205 (locks), and HikariPool (connection pools). This post is socket-layer only.

1. Read the error first: socket vs. TCP

The key insight: if you don't specify a host, or you use -h localhost, the mysql client tries a Unix domain socket file, not TCP. So this error does not mean "the port is blocked." It means "the socket file is missing or unreadable."

The number in parentheses is the decisive clue.

DisplayerrnoMeaningDirection
(2)ENOENTFile does not existService not running / path mismatch
(13)EACCESFile exists, permission deniedOwnership, AppArmor, SELinux

And a one-line map so you don't mix this up with similar errors:

ErrorLayerMeaning
ERROR 2002 ... through socket ... (2)Unix socketSocket file missing
ERROR 2003 ... can't connect ... (111)TCP 3306Connecting via port, connection refused
... through socket ... Connection refusedSocketFile exists, but the server isn't accepting

2. Cause branch table: narrow candidates in 60 seconds

#CauseTypical symptom
mysqld not running / crashedSocket file itself is missing (2)
Wrong socket path (my.cnf mismatch)Service is up, but the client looks in the wrong place
Permissions, ownership, AppArmorFile exists, (13) Permission denied
Environment that must use TCPRemote / split-container setup
No socket inside a Docker containerApp container has no mysqld
Disk full / stale leftover socketCrash left a .sock behind; restart fails

Rule: top to bottom. Skip ①–③ and jump to ④ (TCP workaround) and you may connect today—but the same failure will come back.

3. Diagnostic command set (copy-paste)

(1) Is the service alive?

Bash
systemctl status mysql        # 또는 mariadb
journalctl -u mysql -n 50 --no-pager

Healthy output shows Active: active (running). If it's dead, you've confirmed ①.

(2) Is it actually answering — ping

Bash
mysqladmin ping
# mysqld is alive
mysqladmin -h 127.0.0.1 -P 3306 ping   # TCP로도 확인

(3) Is the socket actually listening?

Bash
ss -lx | grep mysql
# u_str LISTEN 0 70 /var/run/mysqld/mysqld.sock 12345 * 0
ss -ltnp | grep 3306

If ss -lx shows no socket, the server is not opening one.

(4) Path the client expects vs. path the server created — the core of ②

Bash
mysqld --verbose --help | grep '^socket'      # 서버가 만드는 경로
my_print_defaults mysql mysqld | grep socket  # 설정 파일 실제 값
find / -name 'mysqld.sock' 2>/dev/null         # 실제 파일 위치

If the three values disagree, you've confirmed ②.

(5) Permissions, AppArmor, disk

Bash
ls -la /var/run/mysqld/
aa-status | grep mysqld
dmesg | grep -i denied
df -h /var /tmp

4. Prescriptions by cause

① Start the service / recover from a crash

Bash
sudo systemctl start mysql && systemctl is-active mysql

If it crashed, chase [ERROR] lines in the logs.

Bash
journalctl -u mysql -n 100 --no-pager | grep -i error

mysqld_safe --skip-grant-tables disables authentication, so treat it as a last resort and restart normally immediately after recovery.

② Align the socket path (the most common real cause)

The path [mysqld] creates and the path [client]/[mysql] look for must be identical. /etc/mysql/my.cnf:

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

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

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

In a pinch, a symlink works as a temporary bypass (it may vanish on reboot, so the real fix is the config above):

Bash
sudo ln -s /tmp/mysql.sock /var/run/mysqld/mysqld.sock

③ Permissions, ownership, AppArmor

If you see (13), start with ownership:

Bash
sudo chown mysql:mysql /var/run/mysqld && sudo chmod 755 /var/run/mysqld

If AppArmor/SELinux is blocking (default policies on recent distros have gotten stricter):

Bash
sudo aa-complain /usr/sbin/mysqld   # 또는 프로파일에 소켓 경로 추가

⚠️ chmod 777 mysqld.sock is a shortcut to a security incident. Never do it.

④ Switch to TCP — the critical difference between localhost and 127.0.0.1

This is the heart of the post. localhost uses a Unix socket; 127.0.0.1 uses TCP. If the socket is broken, fall back to TCP.

Bash
mysql -h 127.0.0.1 -P 3306 --protocol=TCP -u user -p

Application config follows the same rule.

TEXT
JDBC: jdbc:mysql://127.0.0.1:3306/db
PHP PDO: mysql:host=127.0.0.1;port=3306;dbname=db

In PHP, host=localhost makes PDO use the socket—that's a classic ERROR 2002 cause.

⑤ Docker environments

Containers are not a systemd host. There is no mysqld socket inside the app container. Connect over TCP using the service name, not a socket.

Bash
# docker-compose: db 서비스로 TCP 접속
mysql -h db -P 3306 -u root -p
# 같은 호스트라면 소켓 볼륨 마운트도 가능
#   -v /var/run/mysqld:/var/run/mysqld
# 컨테이너 내부 직접 접속 (이건 소켓이 존재)
docker exec -it mysql mysql -u root -p

Rootless containers add extra socket-mount permission issues, so prefer a TCP setup.

⑥ Disk full / stale socket

Bash
df -h /var /tmp        # 100% 이면 정리 먼저
sudo rm /var/run/mysqld/mysqld.sock   # 크래시 잔존 소켓 제거
sudo systemctl restart mysql

A note from the field

In production, about 70% of ERROR 2002 cases are actually ② (path mismatch) and ④ (localhost vs. 127.0.0.1 mixed). I once spent days chasing a ghost outage where the PHP app used localhost (socket) and a batch script used 127.0.0.1 (TCP)—some things worked, some didn't. The takeaway is simple: the whole team standardizes on one connection method (socket everywhere, or TCP via 127.0.0.1) and this error almost disappears.

4-step checklist & anti-patterns

Memorize the recovery order:

  1. Is the service up? (systemctl status)
  2. Is the path right? (mysqld --verbose --help vs my_print_defaults)
  3. Are permissions right? (ls -la, errno (13))
  4. Can you fall back to TCP? (-h 127.0.0.1)

Anti-patterns to avoid:

  • ❌ Blind chmod 777 mysqld.sock — security risk
  • ❌ Running --skip-grant-tables in production without knowing why
  • ❌ Restarting over and over without deleting a stale socket
  • ❌ Mixing localhost and 127.0.0.1 and looping on the same error

FAQ

Q. Why does localhost fail while 127.0.0.1 works? A. localhost connects via a Unix socket file; 127.0.0.1 connects via TCP 3306. If the socket file is broken, only localhost fails and 127.0.0.1 works.

Q. What's the difference between errno (2) and (13)? A. (2) is ENOENT: the socket file itself is missing (service not running / path mismatch). (13) is EACCES: the file exists but permission is denied (ownership, AppArmor/SELinux).

Q. I get ERROR 2002 from a Docker app container. A. There is no mysqld socket inside the app container. Connect over TCP with -h db (the DB service name), or volume-mount /var/run/mysqld if you're on the same host.

JSON-LD (FAQPage) snippet:

JSON
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {"@type":"Question","name":"Why does localhost fail while 127.0.0.1 works?","acceptedAnswer":{"@type":"Answer","text":"localhost uses a Unix socket; 127.0.0.1 uses TCP 3306. If the socket file is broken, only 127.0.0.1 works."}},
    {"@type":"Question","name":"What's the difference between errno (2) and (13)?","acceptedAnswer":{"@type":"Answer","text":"(2) ENOENT means the socket file is missing; (13) EACCES means the file exists but permission is denied."}},
    {"@type":"Question","name":"How do I find the socket path?","acceptedAnswer":{"@type":"Answer","text":"Compare mysqld --verbose --help | grep '^socket' with my_print_defaults mysql mysqld | grep socket."}},
    {"@type":"Question","name":"What if I get ERROR 2002 in Docker?","acceptedAnswer":{"@type":"Answer","text":"The app container has no socket, so connect over TCP using the DB service name, or volume-mount /var/run/mysqld."}}
  ]
}
확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.