서버 환경을 새로 구축하거나 잘 구동되던 웹 서비스에서 갑자기 "ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)" 혹은 "(111)" 에러를 마주친 적이 있을 것이다. 소스 코드는 전혀 수정하지 않았는데 갑자기 DB 접속이 안 되어 당황했던 경험이 한 번쯤은 있을 것이다. 다만 대부분의 개발자들은 이 에러가 발생하면 소켓 파일 위치나 소켓 통신과 TCP/IP 통신의 차이를 모른 채 무작정 서버를 재부팅하거나 인터넷에서 검색한 chown 명령어를 무지성으로 따라치곤 한다. 이번에는 MySQL ERROR 2002 에러가 정확히 왜 발생하는지, 소켓 방식과 TCP/IP 접속 방식의 원리는 무엇인지, 그리고 상황별 원인과 해결 방법을 완벽하게 정리해서 소개하겠다.
MySQL 데몬에 접속할 때 발생하는 ERROR 2002(HY000)는 클라이언트가 MySQL 서버와 통신 채널을 형성하지 못했을 때 발생하는 대표적인 연결 오류다. 리눅스 환경에서 localhost로 접속을 시도할 경우, MySQL 클라이언트는 기본적으로 네트워크(TCP/IP) 포트를 타지 않고 로컬 유닉스 도메인 소켓(Unix Domain Socket, 예: /tmp/mysql.sock 또는 /var/run/mysqld/mysqld.sock)을 통해 직접 통신을 시도한다.
이때 발생하는 주요 에러 메시지의 차이는 다음과 같다.
| 에러 번호/메시지 | 주요 원인 | 설명 |
|---|---|---|
| (2) No such file or directory | 소켓 파일 부재 / 경로 불일치 | mysqld 서비스가 정지되어 소켓 파일이 생성되지 않았거나, my.cnf의 소켓 경로가 서로 다름 |
| (111) Connection refused | 데몬 미구동 / 포트 차단 | MySQL 프로세스가 비정상 종료되었거나, TCP/IP 포트(3306)가 닫혀 있음 |
| (13) Permission denied | 소켓 파일 접근 권한 부족 | 소켓 파일이 속한 디렉토리나 파일 자체의 소유권/권한 설정 문제 |
ERROR 2002를 해결하기 위해서는 차근차근 점검 절차를 거쳐야 한다. 단순히 소켓 파일 경로만 바꾼다고 해결되지 않는 경우가 많기 때문이다.
가장 흔한 원인은 MySQL 서비스 자체가 멈춰있는 경우다. 데몬이 실행 중이지 않으면 당연히 소켓 파일도 생성되지 않는다.
# 서비스 상태 확인
systemctl status mysqld
# 서비스가 꺼져 있다면 재시작
systemctl start mysqld
MySQL 서버 설정파일(/etc/my.cnf 또는 /etc/mysql/my.cnf)에서 정의된 소켓 위치와 클라이언트(PHP, CLI)가 찾아가는 위치가 다를 때 발생한다. my.cnf 파일 내 [mysqld] 영역과 [client] 영역의 socket 경로를 동일하게 맞춰주어야 한다.
[mysqld]
socket=/var/run/mysqld/mysqld.sock
[client]
socket=/var/run/mysqld/mysqld.sock
급하게 서비스를 복구해야 할 때 유용한 팁이다. DB 호스트명을 localhost로 지정하면 유닉스 소켓 통신을 시도하지만, 127.0.0.1로 지정하면 Loopback TCP/IP 통신을 하므로 소켓 파일 문제 영역을 즉시 우회할 수 있다.
실제 애플리케이션 코드 및 환경 설정에서 이 오류가 발생하는 경우와 이를 해결하는 방법을 살펴보자.
먼저 설정 오류로 인해 접속이 실패하는 잘못된 PHP PDO 예제 코드다.
✗ 잘못된 코드 (localhost 사용 시 소켓 파일 경로 불일치로 인한 예외 발생)
<?php
// localhost 사용 시 기본 유닉스 소켓 경로를 찾지만, 서버 환경과 맞지 않아 2002 에러 발생
$dsn = "mysql:host=localhost;dbname=testdb;charset=utf8mb4";
$username = "dbuser";
$password = "secret1234";
try {
$pdo = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
// SQLSTATE[HY000] [2002] Can't connect to local MySQL server... 에러 출력
echo "연결 실패: " . $e->getMessage();
}
?>다음은 TCP/IP 방식을 명시하거나 unix_socket 경로를 직접 지정하여 접속을 성공시키는 올바른 코드다.
✓ 올바른 코드 (127.0.0.1 명시 또는 unix_socket 경로 직접 지정)
<?php
$username = "dbuser";
$password = "secret1234";
// 해결 방법 A: 127.0.0.1을 사용하여 TCP/IP 통신으로 소켓 이슈 우회
$dsn_tcp = "mysql:host=127.0.0.1;port=3306;dbname=testdb;charset=utf8mb4";
// 해결 방법 B: unix_socket 경로를 명확하게 지정하여 소켓 연결
$dsn_socket = "mysql:host=localhost;dbname=testdb;unix_socket=/var/run/mysqld/mysqld.sock;charset=utf8mb4";
try {
$pdo = new PDO($dsn_tcp, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
echo "MySQL 연결 성공!";
} catch (PDOException $e) {
echo "연결 실패: " . $e->getMessage();
}
?>실행 결과:
MySQL 연결 성공!
ERROR 2002를 해결할 때 자주하는 실수와 주의해야 할 포인트들을 정리해보았다.
- ✗ 무작정 chmod 777 부여: 소켓 파일이 안 열린다고 /tmp나 소켓 디렉토리에 chmod 777을 남발하는 것은 심각한 보안 위협이다.
- ✓ 올바른 소유권 설정: chown -R mysql:mysql /var/run/mysqld 와 같이 해당 디렉토리와 파일의 소유권을 mysql 계정으로 정확히 지정해야 한다.
- ✗ my.cnf 수정 후 재시작 누락: /etc/my.cnf의 소켓 경로를 수정해놓고 systemctl restart mysqld를 실행하지 않으면 설정이 적용되지 않는다.
- ✓ php.ini의 default_socket 확인: PHP 웹 환경에서는 php.ini의 pdo_mysql.default_socket 또는 mysqli.default_socket 설정이 실제 mysqld 소켓 위치와 일치하는지도 점검해야 한다.
MySQL ERROR 2002 에러는 결국 **"MySQL 데몬이 정상 구동되지 않았거나, 클라이언트와 서버가 서로 다른 소켓 경로를 바라보고 있거나, 접근 권한 문제로 소켓 파일을 읽을 수 없는 현상"**이다. 문제 원인을 파악할 때 무작정 복사해온 명령어들을 실행하기보다, 데몬 상태 확인 -> localhost 대 127.0.0.1 차이 이해 -> my.cnf 소켓 경로 점검 순으로 접근하는 것이 정석이다.
안정적인 DB 통신은 웹 애플리케이션 동작의 기본이다. 이번 글에서 다룬 소켓 통신 원리와 설정 점검 포인트를 잘 기억해두고, 추후 디버깅 시 127.0.0.1 우회 테스트와 my.cnf 소켓 경로 통일 작업을 차근차근 진행해보자. 문제 상황을 정확히 진단하는 작은 습관이 모여 서비스 안정성을 획기적으로 높여줄 것이다.