Помню свой первый настоящий проект на Laravel. Всё работало идеально на тестовом сервере, но стоило развернуть приложение на новой машине, как появилось это проклятое сообщение: "ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'". Тогда я потратил почти сутки, перелопачивая форумы и документацию. Сегодня разберу эту ошибку так, как мне самому не хватало тогда понимания.

Суть проблемы в том, что клиент MySQL пытается подключиться к серверу через Unix-сокет, а что-то идёт не так. На Unix-подобных системах локальные соединения работают не через TCP/IP порты, а через специальный файл-сокет. Это быстрее и эффективнее для локальных подключений. Когда вы пишете mysql -u root -p без указания хоста, система автоматически ищет этот файл. И если его нет, повреждён путь или закрыт доступ, получаете ошибку 2002.

Для веб-разработчика это может означать полную остановку работы. PHP-приложение выдаёт PDOException, Node.js скрипты падают с таймаутом, Laravel миграции зависают. Пока не разберёшься с корнем проблемы, никакой код не поможет.

Невидимый сервер: когда процесса просто нет

Первая и самая частая причина банальна до неприличия: MySQL или MariaDB просто не запущен. Никакого демона mysqld в памяти, никакого сокет-файла на диске. Клиент стучится в пустоту и получает "No such file or directory".

Проверяю статус сервиса командой, которая стала для меня второй натурой:

systemctl status mysql

Для MariaDB меняю на systemctl status mariadb. Если вижу "inactive (dead)" или "failed", значит сервер мёртв. Иногда статус показывает "active (exited)", что тоже плохо - процесс попытался запуститься и сразу завершился.

Запускаю сервис:

sudo systemctl start mysql

В половине случаев этого достаточно. Но если запуск проваливается, начинается настоящая детективная работа. Смотрю журнал ошибок:

sudo journalctl -xeu mysql

Или классический лог-файл:

sudo tail -n 100 /var/log/mysql/error.log

Однажды столкнулся с ситуацией, когда сервер не мог запуститься из-за того, что предыдущий процесс некорректно завершился и оставил lock-файл. В логах было сообщение о невозможности получить блокировку. Удалил старый lock, и всё заработало. В другой раз проблема оказалась в нехватке оперативной памяти - система убила процесс через OOM killer, о чём честно написала в системном журнале.

Проверяю дисковое пространство:

df -h

Если раздел с /var заполнен на 100%, MySQL физически не может создать сокет-файл и записывать логи. Очищаю старые файлы, и проблема решается.

После успешного запуска настраиваю автозапуск:

sudo systemctl enable mysql

Теперь после перезагрузки сервера база поднимется сама, без моего участия.

Потерянный адрес: когда клиент и сервер говорят на разных языках

Вторая причина коварнее. Сервер работает, процесс mysqld висит в памяти, но клиент всё равно не может подключиться. Почему? Потому что ищет сокет-файл не там, где его создал сервер.

Типичная ситуация: сервер положил сокет в /var/run/mysqld/mysqld.sock, а клиент ожидает /tmp/mysql.sock. Или наоборот. Такое происходит после обновления системы, миграции между дистрибутивами, установки нескольких версий MySQL/MariaDB одновременно.

Проверяю, существует ли файл:

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

Если файла нет, смотрю конфигурацию сервера. Открываю /etc/mysql/my.cnf или /etc/mysql/mysql.conf.d/mysqld.cnf (на Ubuntu) и ищу параметр socket в секции [mysqld]:

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

Затем проверяю настройки клиента в секции [client]:

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

Эти пути должны совпадать! Если сервер настроен на один путь, а клиент на другой, соединение невозможно. Исправляю несоответствие, сохраняю файл и перезапускаю службу.

На практике встречал ситуацию, когда на одном сервере стояли и MySQL 5.7, и MariaDB 10.5. У каждого свой конфиг, свой путь к сокету. Попытка подключиться приводила к хаосу - система не понимала, к какому серверу обращаться. Решение: удалить одну из СУБД полностью.

Проверить, какие пакеты установлены:

dpkg -l | grep mysql
dpkg -l | grep mariadb

Если вижу конфликтующие версии, удаляю лишнее:

sudo apt-get purge mysql-*

Есть хитрый способ обойти проблему сокета временно - подключиться через TCP/IP:

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

Обратите внимание: использую IP-адрес 127.0.0.1, а не localhost. Когда указываете localhost, MySQL автоматически пытается использовать Unix-сокет. Когда указываете IP - переключается на TCP/IP соединение. Если через IP подключение работает, а через localhost нет, проблема точно в сокете.

Для PHP-приложений явно указываю путь в DSN:

$pdo = new PDO('mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=myapp', 'user', 'pass');

В Node.js с библиотекой mysql2:

const connection = mysql.createConnection({
  socketPath: '/var/run/mysqld/mysqld.sock',
  user: 'root',
  database: 'myapp'
});

Это избавляет от неопределённости и делает поведение предсказуемым.

Закрытые двери: когда права доступа рушат всё

Третья причина касается прав доступа к сокет-файлу и директории, где он лежит. Даже если сервер запущен и путь правильный, без корректных разрешений клиент не сможет прочитать или записать в сокет.

Проверяю владельца и права:

ls -ld /var/run/mysqld/
ls -l /var/run/mysqld/mysqld.sock

Правильный вывод выглядит примерно так:

drwxr-xr-x 2 mysql mysql 60 Oct 28 10:00 /var/run/mysqld/
srwxrwxrwx 1 mysql mysql 0 Oct 28 10:00 /var/run/mysqld/mysqld.sock

Директория и файл должны принадлежать пользователю mysql и группе mysql. Если вижу другого владельца (например, root), это проблема. Исправляю:

sudo chown -R mysql:mysql /var/run/mysqld/
sudo chmod 755 /var/run/mysqld/

После изменения прав перезапускаю службу:

sudo systemctl restart mysql

Столкнулся однажды с ситуацией на Ubuntu Server, где после обновления пакетов AppArmor начал блокировать доступ MySQL к собственному сокету. Проверяю статус:

sudo aa-status

Если профиль mysql активен и есть нарушения, редактирую правила в /etc/apparmor.d/usr.sbin.mysqld. Добавляю разрешение:

/run/mysqld/mysqld.sock rw,

Перезагружаю профиль:

sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld

На CentOS с SELinux проблемы похожие. Восстанавливаю контекст безопасности:

sudo restorecon -Rv /var/run/mysqld

Важный момент: никогда не ставьте права 777 на сокет или директорию, даже если это решает проблему. Это дыра в безопасности размером с ворота. Правильные права - 755 для директории и 660 для сокета.

Продвинутая диагностика: когда базовые шаги не помогли

Бывают случаи, когда стандартный алгоритм не работает. Тогда копаю глубже.

Проверяю, какие процессы слушают сокеты:

netstat -ln | grep mysql

Или с помощью ss:

ss -xl | grep mysql

Если ничего не показывает, значит сервер точно не создал сокет. Если показывает, но подключиться не получается, проблема в правах или конфигурации клиента.

Смотрю, какие конфигурационные файлы загружает MySQL:

mysql --help | grep my.cnf

Система может читать несколько файлов в определённом порядке: /etc/my.cnf, /etc/mysql/my.cnf, ~/.my.cnf. Последний перезаписывает предыдущие. Если где-то в цепочке указан неправильный путь, получаю конфликт.

Проверяю параметр bind-address в конфигурации. Если он установлен как bind-address = ::1 (только IPv6), а система пытается подключиться через IPv4, могут быть проблемы. Меняю на:

bind-address = 127.0.0.1

Иногда помогает создание символической ссылки между путями:

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

Но это костыль, а не решение. Правильнее унифицировать конфигурацию.

Контейнеры и виртуализация: отдельный круг проблем

При работе с Docker ошибка 2002 приобретает новые измерения. Внутри контейнера путь к сокету может отличаться от хостовой системы. Если монтируете volume неправильно, клиент снаружи не увидит сокет изнутри.

В docker-compose.yml правильно настраиваю volume:

services:
  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql
      - /var/run/mysqld:/var/run/mysqld
    environment:
      MYSQL_ROOT_PASSWORD: secret

Для приложений внутри контейнеров всегда использую TCP-соединение, а не сокеты. Это проще и надёжнее:

services:
  web:
    image: myapp
    environment:
      DB_HOST: db
      DB_PORT: 3306

В облачных окружениях вроде AWS RDS или Google Cloud SQL сокеты вообще не используются - только TCP/IP. Настраиваю подключение соответственно.

Финальный чеклист действий

Когда сталкиваюсь с ERROR 2002, прохожу по этому списку:

  1. Проверяю статус службы: systemctl status mysql
  2. Если не запущена, стартую: sudo systemctl start mysql
  3. Смотрю логи при проблемах запуска: journalctl -xeu mysql
  4. Проверяю наличие сокета: ls -l /var/run/mysqld/mysqld.sock
  5. Сверяю пути в конфигах сервера и клиента
  6. Проверяю права: ls -ld /var/run/mysqld/
  7. Исправляю владельца при необходимости: chown mysql:mysql
  8. Пробую TCP-соединение: mysql -h 127.0.0.1
  9. Проверяю AppArmor/SELinux
  10. Перезапускаю службу после изменений

Этот алгоритм решает проблему в 95% случаев. Оставшиеся 5% требуют глубокого анализа специфики окружения.

За годы работы с базами данных понял главное: ERROR 2002 выглядит страшно только для новичка. Понимание механизма Unix-сокетов превращает диагностику в рутину. Систематический подход, внимание к логам и знание трёх основных причин позволяют решать проблему за минуты, а не часы.