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.
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.
| Display | errno | Meaning | Direction |
|---|---|---|---|
(2) | ENOENT | File does not exist | Service not running / path mismatch |
(13) | EACCES | File exists, permission denied | Ownership, AppArmor, SELinux |
And a one-line map so you don't mix this up with similar errors:
| Error | Layer | Meaning |
|---|---|---|
ERROR 2002 ... through socket ... (2) | Unix socket | Socket file missing |
ERROR 2003 ... can't connect ... (111) | TCP 3306 | Connecting via port, connection refused |
... through socket ... Connection refused | Socket | File exists, but the server isn't accepting |
2. Cause branch table: narrow candidates in 60 seconds
| # | Cause | Typical symptom |
|---|---|---|
| ① | mysqld not running / crashed | Socket file itself is missing (2) |
| ② | Wrong socket path (my.cnf mismatch) | Service is up, but the client looks in the wrong place |
| ③ | Permissions, ownership, AppArmor | File exists, (13) Permission denied |
| ④ | Environment that must use TCP | Remote / split-container setup |
| ⑤ | No socket inside a Docker container | App container has no mysqld |
| ⑥ | Disk full / stale leftover socket | Crash 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?
systemctl status mysql # 또는 mariadb
journalctl -u mysql -n 50 --no-pagerHealthy output shows Active: active (running). If it's dead, you've confirmed ①.
(2) Is it actually answering — ping
mysqladmin ping
# mysqld is alive
mysqladmin -h 127.0.0.1 -P 3306 ping # TCP로도 확인(3) Is the socket actually listening?
ss -lx | grep mysql
# u_str LISTEN 0 70 /var/run/mysqld/mysqld.sock 12345 * 0
ss -ltnp | grep 3306If ss -lx shows no socket, the server is not opening one.
(4) Path the client expects vs. path the server created — the core of ②
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
ls -la /var/run/mysqld/
aa-status | grep mysqld
dmesg | grep -i denied
df -h /var /tmp4. Prescriptions by cause
① Start the service / recover from a crash
sudo systemctl start mysql && systemctl is-active mysqlIf it crashed, chase [ERROR] lines in the logs.
journalctl -u mysql -n 100 --no-pager | grep -i errormysqld_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:
[mysqld]
socket = /var/run/mysqld/mysqld.sock
[client]
socket = /var/run/mysqld/mysqld.sock
[mysql]
socket = /var/run/mysqld/mysqld.sockIn a pinch, a symlink works as a temporary bypass (it may vanish on reboot, so the real fix is the config above):
sudo ln -s /tmp/mysql.sock /var/run/mysqld/mysqld.sock③ Permissions, ownership, AppArmor
If you see (13), start with ownership:
sudo chown mysql:mysql /var/run/mysqld && sudo chmod 755 /var/run/mysqldIf AppArmor/SELinux is blocking (default policies on recent distros have gotten stricter):
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.
mysql -h 127.0.0.1 -P 3306 --protocol=TCP -u user -pApplication config follows the same rule.
JDBC: jdbc:mysql://127.0.0.1:3306/db
PHP PDO: mysql:host=127.0.0.1;port=3306;dbname=dbIn 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.
# 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 -pRootless containers add extra socket-mount permission issues, so prefer a TCP setup.
⑥ Disk full / stale socket
df -h /var /tmp # 100% 이면 정리 먼저
sudo rm /var/run/mysqld/mysqld.sock # 크래시 잔존 소켓 제거
sudo systemctl restart mysqlA 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:
- Is the service up? (
systemctl status) - Is the path right? (
mysqld --verbose --helpvsmy_print_defaults) - Are permissions right? (
ls -la, errno(13)) - 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-tablesin production without knowing why - ❌ Restarting over and over without deleting a stale socket
- ❌ Mixing
localhostand127.0.0.1and 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:
{
"@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."}}
]
}Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
Comments
Be the first to comment.