Ошибка MySQL «Can't connect through socket»: причины и решение
У ошибки сокета есть пять реалистичных причин. Как за пять минут выяснить, какая из них ваша, и почему localhost и 127.0.0.1 не одно и то же.
Это сообщение появляется всегда в самый неподходящий момент: после перезагрузки, после обновления или когда ночью закончилось место на накопителе. Формулировка почти всегда одна и та же:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
В нём есть две детали, которые многие пропускают: путь и число в скобках. Обе довольно точно указывают, где искать. Эта статья разбирает пять реалистичных причин (служба не запущена, неверный путь к сокету в конфигурации, приложение ожидает не тот путь, который использует сервер, проблема с правами, закончилось место на накопителе), показывает диагностику в том порядке, который быстрее всего приводит к цели, и объясняет разницу между localhost и 127.0.0.1, которая сама по себе снимает примерно половину всех случаев.
Внимательно читаем сообщение об ошибке
Клиент попытался подключиться через Unix-domain-сокет, то есть через файл в файловой системе, а не по сети. Путь в кавычках — это путь, которого ожидает клиент. Использует ли сервер тот же самый путь, сообщение не говорит. Именно здесь чаще всего и кроется проблема.
Число в конце — это код ошибки операционной системы:
| Код | Значение | Что это означает на практике |
|---|---|---|
| (2) | No such file or directory | Файла сокета не существует. Служба не запущена либо путь указан неверно. |
| (13) | Permission denied | Файл существует, но вызывающий пользователь не имеет права его открыть. |
| (111) | Connection refused | Файл существует, но никто на нём не слушает. Классический остаток после аварийного завершения работы. |
В зависимости от клиента и версии формулировка меняется. Все эти варианты означают одно и то же:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
ERROR 2002 (HY000): Can't connect to local server through socket '/run/mysqld/mysqld.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 '/tmp/mysql.sock' (2)
Из PHP та же самая ошибка выглядит так, потому что PHP пробрасывает наружу только голый errno:
PDOException: SQLSTATE[HY000] [2002] No such file or directory
Warning: mysqli_connect(): (HY000/2002): No such file or directory
Важно не перепутать: ERROR 2003 означает совсем другое. Там вместо пути стоят IP-адрес и порт, то есть речь идёт о подключении по TCP. А ERROR 1045 (28000): Access denied for user говорит о том, что соединение состоялось и не удался только вход. Об этом у нас есть отдельная статья: Как исправить ошибку MySQL «Access denied for user».
localhost или 127.0.0.1: разница, которая объясняет половину случаев
MySQL и MariaDB считают localhost особым случаем. Если там указано буквально localhost, клиентская библиотека полностью игнорирует имя хоста и подключается через Unix-сокет. Если там указано 127.0.0.1, соединение идёт по TCP на порт 3306. Это не мелочь, а самая суть проблемы: приложение с localhost в конфигурации обращается к серверу через файл, путь к которому оно берёт совсем не оттуда, откуда его берёт сервер.
Поэтому самая быстрая проверка того, работает ли сервер вообще, выглядит так:
mysql --protocol=TCP -h 127.0.0.1 -P 3306 -u root -p
Если здесь появляется запрос пароля или Access denied, значит служба работает и у вас чистая проблема с сокетом. Если приходит ERROR 2003 ... (111), служба не запущена или не слушает TCP.
Как постоянное решение переход на 127.0.0.1 всё же остаётся вариантом второго сорта. Сокет быстрее, он обходит сетевой стек и снаружи принципиально недоступен. Но главное вот что: запись 'app'@'localhost' в таблице пользователей не действует автоматически и для 'app'@'127.0.0.1'. Тот, кто поменял хост в приложении и получил после этого Access denied, наткнулся ровно на этот эффект. И если вы переходите на TCP, проверьте, что bind-address не выставлен по недосмотру в 0.0.0.0 и база данных не оказалась внезапно доступна из интернета. К этой теме подходят статьи Защита MariaDB и MySQL и Настройка файрвола UFW.
Диагностика за пять минут
Шаг 1: работает ли служба вообще?
systemctl status mariadb
systemctl status mysql
В Debian и Ubuntu юнит MariaDB называется mariadb.service (с mysql.service в качестве алиаса), у MySQL это mysql.service. В AlmaLinux, Rocky Linux и RHEL он называется mariadb.service и, соответственно, mysqld.service. Интересна строка Active:. Если там стоит active (running), переходите сразу к шагу 2. Если там стоит failed (Result: exit-code) или inactive (dead), причину следует искать в журнале ошибок.
Шаг 2: какой путь к сокету сервер использует на самом деле?
Это можно прочитать из конфигурационных файлов и без запущенного сервера. my_print_defaults разбирает ту же цепочку файлов, что и сам сервер, включая все подключаемые. Указывайте при этом сразу все подходящие группы, тогда команда сработает в любом дистрибутиве:
my_print_defaults client client-server mysqld mariadbd | grep -i socket
Четыре имени групп — это не перестраховка, а ответ на три подводных камня, каждый из которых по отдельности даёт пустой вывод. my_print_defaults client не выдаёт вообще ничего ни в одном из проверенных дистрибутивов, потому что в 50-client.cnf и, соответственно, в /etc/my.cnf.d/client.cnf все опции закомментированы. В Debian и Ubuntu сокет вместо этого прописан в группе [client-server] файла /etc/mysql/mariadb.cnf и появляется там как --socket=/run/mysqld/mysqld.sock. В семействе Red Hat такой группы не существует, там значение --socket=/var/lib/mysql/mysql.sock отдаёт группа mysqld. А начиная с MariaDB 11.8, то есть с Debian 13, серверная группа в 50-server.cnf называется уже не [mysqld], а [mariadbd]. Тот, кто вызовет там только my_print_defaults mysqld, увидит пустой вывод и ошибочно решит, что его конфигурация пуста.
Как вариант, если сервер работает и вы можете в него войти:
mysql -e "SHOW VARIABLES LIKE 'socket'"
А совсем без входа в базу, спросив напрямую у ядра, какие Unix-сокеты заняты:
ss -lx | grep -i mysql
Если оболочка отвечает ss: command not found, значит просто не установлен пакет. В Debian и Ubuntu он называется iproute2, в AlmaLinux, Rocky Linux и Oracle Linux — iproute:
apt-get install -y iproute2
dnf install -y iproute
Теперь у вас есть путь, который сервер действительно предоставляет. Сравните его посимвольно с путём из сообщения об ошибке. /run/mysqld/mysqld.sock и /var/run/mysqld/mysqld.sock на современных системах одно и то же, потому что /var/run — это символьная ссылка на /run. А вот /var/lib/mysql/mysql.sock и /tmp/mysql.sock таким свойством не обладают.
Шаг 3: существует ли файл и кому он принадлежит?
ls -la /run/mysqld/
ls -la /var/lib/mysql/mysql.sock
Ожидается файл типа s (сокет), владелец mysql:mysql, права srwxrwxrwx. Каталог уровнем выше должен выглядеть как drwxr-xr-x mysql mysql. Если каталога /run/mysqld нет вовсе, значит сервер ни разу не стартовал успешно, ведь этот каталог создаётся при запуске.
Шаг 4: читаем журнал ошибок
Здесь дистрибутивы расходятся сильнее всего, и здесь же скрыта самая частая причина, по которой инструкции из интернета не помогают. В Ubuntu с MySQL сервер пишет в /var/log/mysql/error.log. В Debian с MariaDB параметр log_error по умолчанию закомментирован, каталога /var/log/mysql/ там вообще нет, и всё попадает в журнал systemd. Поэтому берите ту строку, которая подходит именно к вашей комбинации:
| Система и сервер | Команда |
|---|---|
| Debian или Ubuntu, MariaDB | journalctl -u mariadb --no-pager -n 50 |
| Debian или Ubuntu, MySQL | tail -n 50 /var/log/mysql/error.log |
| AlmaLinux, Rocky, RHEL, MySQL | tail -n 50 /var/log/mysql/mysqld.log |
| AlmaLinux, Rocky, RHEL, MariaDB | tail -n 50 /var/log/mariadb/mariadb.log |
Одна ловушка заслуживает особого внимания, потому что она не выдаёт никакой ошибки: в системе Debian с MariaDB mysql.service — это всего лишь алиас на mariadb.service. systemctl алиас разрешает, а журнал индексирует записи под настоящим именем юнита. journalctl -u mysql отвечает там -- No entries -- и кодом возврата 0, хотя журнал полон. Тот, кто попробует только эту команду, сочтёт журнал пустым и продолжит искать не в том месте. В обратную сторону действует то же самое: в системе Ubuntu с MySQL команда journalctl -u mariadb тоже выдаёт -- No entries --. Если вы не уверены, о каком юните идёт речь, спросите оба сразу:
journalctl -u 'mysql*' -u 'mariadb*' --no-pager -n 50
Если вам нужен постоянный журнал, добавьте в Debian и Ubuntu в файл /etc/mysql/mariadb.conf.d/50-server.cnf в серверную группу строку log_error = /var/log/mysql/error.log, создайте каталог командой install -d -o mysql -g mysql /var/log/mysql и перезапустите службу.
Причина 1: служба не запущена (и почему)
systemctl start mariadb — это рефлекс, но если служба только что умерла сама по себе, она, как правило, тут же снова упрётся в ту же ошибку. Сначала стоит поискать в журнале три конкретных признака.
Закончилось место на накопителе
InnoDB отказывается стартовать, как только не может писать redo-логи. Типичные строки:
[ERROR] InnoDB: Write to file ./ib_logfile0 failed at offset 0, 1048576 bytes should have been written, only 0 were written
[ERROR] InnoDB: Error number 28 means 'No space left on device'
Can't create/write to file (Errcode: 28 "No space left on device")
Проверьте и то, и другое: свободное место и свободные inode:
df -h
df -i
Исчерпанные inode при, казалось бы, свободном месте встречаются чаще, чем принято думать, обычно из-за миллионов мелких файлов сессий или cache. Что можно удалять безопасно, а что нельзя, разобрано в статье Диск заполнен: как освободить место на Linux-сервере. В каталоге /var/lib/mysql ни в коем случае не удаляйте ничего вручную, особенно файлы ib_logfile во время идущего восстановления.
OOM-killer оказался быстрее
Если служба исчезает прямо во время работы и без сообщения об ошибке, часто вмешалось ядро:
dmesg -T | grep -i -E "oom|killed process"
journalctl -k | grep -i oom
Строка вида Out of memory: Killed process 1234 (mysqld) не оставляет сомнений. Ошибка сокета в этом случае лишь симптом. Средства против этого: уменьшить innodb_buffer_pool_size, сократить число одновременных PHP-воркеров или добавить немного swap в качестве буфера, см. статью Настройка swap против нехватки памяти.
Осиротевший файл сокета после сбоя
Если в журнале вы видите такое:
[ERROR] Do you already have another mysqld server running on socket: /run/mysqld/mysqld.sock ?
[ERROR] Aborting
значит где-то лежит файл сокета, которому не соответствует ни один процесс. Сначала убедитесь, что сервер действительно не работает, и только потом удаляйте файл:
systemctl stop mariadb
pgrep -a mysqld
rm -f /run/mysqld/mysqld.sock
systemctl start mariadb
Если pgrep всё ещё показывает процесс, файл удалять нельзя. Иначе все работающие приложения потеряют своё соединение, а сервер при следующем запуске создаст файл заново, пока старый процесс продолжает жить.
Причина 2: сервер и приложение имеют в виду разные пути
Это тот случай, когда всё работает и всё равно ничего не работает: ss -lx показывает /run/mysqld/mysqld.sock, а приложение ищет по пути /tmp/mysql.sock. Типичные источники: самостоятельно собранный сервер, переход с MySQL на MariaDB, переезд с сервера под панелью управления на чистую систему или установка PHP из стороннего репозитория с другими значениями по умолчанию.
Правильный подход: привести путь к одному значению ровно в трёх местах. Во-первых, на стороне сервера. Файл для этого в каждой комбинации называется по-своему: в Debian и Ubuntu с MariaDB это /etc/mysql/mariadb.conf.d/50-server.cnf, в Debian и Ubuntu с MySQL /etc/mysql/mysql.conf.d/mysqld.cnf, в AlmaLinux, Rocky Linux и Oracle Linux /etc/my.cnf.d/mariadb-server.cnf или, соответственно, /etc/my.cnf.d/mysql-server.cnf. Каталога /etc/mysql/ в семействе Red Hat нет вообще, там всё идёт через /etc/my.cnf и /etc/my.cnf.d/:
[mysqld]
socket = /run/mysqld/mysqld.sock
Во-вторых, для консольных утилит, в 50-client.cnf или в отдельном собственном файле:
[client]
socket = /run/mysqld/mysqld.sock
В-третьих, для PHP. Три записи в php.ini должны содержать один и тот же путь, иначе от серверной конфигурации не будет никакого толку:
mysqli.default_socket = /run/mysqld/mysqld.sock
pdo_mysql.default_socket = /run/mysqld/mysqld.sock
mysql.default_socket = /run/mysqld/mysqld.sock
Какой php.ini вообще действует, подскажет php --ini, при условии что установлен пакет php-cli, иначе оболочка ответит только php: command not found. Важнее оговорка, которая стоит за этим: php --ini называет файл командной строки, а именно он у веб-приложения почти никогда не виноват. Решающим является файл FPM, чаще всего /etc/php/8.3/fpm/php.ini, и что там действительно применяется, показывает php-fpm8.3 -i | grep -E 'Loaded Configuration|pdo_mysql.default_socket|mysqli.default_socket'. После изменения нужен перезапуск службы FPM, а не только reload веб-сервера. Если после этого PHP-приложение по-прежнему ничего не отдаёт, следующая остановка часто такая: Как исправить ошибку nginx 502 Bad Gateway.
Для приложений, в которых путь жёстко зашит и которые вы не можете трогать, последней инстанцией остаётся символьная ссылка:
ln -s /run/mysqld/mysqld.sock /tmp/mysql.sock
Правда, перезагрузку это не переживёт, потому что /tmp на многих системах очищается. Постоянное место для такого решения: правило tmpfiles или, что лучше, конфигурация самого приложения.
Причина 3: права и отсутствующий /run/mysqld
Если вы получаете (13) Permission denied, сокет существует, но ваш пользователь до него не добирается. У самого сокета обычно стоят права 0777, так что доступ срывается на каталоге уровнем выше:
chown mysql:mysql /run/mysqld
chmod 755 /run/mysqld
Вторая классика: /run — это tmpfs, а значит после каждой перезагрузки он пуст. Подкаталог /run/mysqld создаётся заново при запуске, либо через systemd-tmpfiles, либо стартовым скриптом. Если при ручной установке подходящее правило так и не появилось, сервер стартует ровно один раз (пока каталог существовал, созданный руками) и после следующей перезагрузки не запускается уже никогда. В этом случае создайте файл /etc/tmpfiles.d/mysql.conf:
d /run/mysqld 0755 mysql mysql -
Применить это без перезагрузки можно командой systemd-tmpfiles --create. Если у вас собственный юнит, вместо этого можно задать RuntimeDirectory=mysqld, см. статью Как создать собственную systemd-службу.
Причина 4: AppArmor и SELinux
Эти двое порождают самый сбивающий с толку вариант ошибки: права в файловой системе выглядят правильно, а сервер всё равно сообщает:
[ERROR] Can't start server: Bind on unix socket: Permission denied
[ERROR] Do you already have another mysqld server running on port: 3306 ?
В Ubuntu пакет MySQL приносит с собой профиль AppArmor. Если вы перенесли путь к сокету в какое-то нестандартное место, профиль запретит создание файла. Отказы попадают не в журнал MySQL, а сюда:
dmesg -T | grep -i apparmor
journalctl -k | grep -i denied
Расширить профиль можно в /etc/apparmor.d/local/usr.sbin.mysqld, туда добавляется строка вида /run/mysqld/my.sock rw,, после чего выполняется systemctl reload apparmor. В AlmaLinux и Rocky Linux аналогом выступает SELinux, там вы проверяете вывод ausearch -m avc -ts recent и задаёте контекст через semanage fcontext и restorecon. В обоих случаях удобнее просто оставить сокет на предусмотренном для него месте по умолчанию.
Различия дистрибутивов одним взглядом
Большинство инструкций утверждают, что путь один и тот же для всех систем. Это не так, и именно на этом срывается копирование чужих решений. По состоянию на июль 2026 года:
| Система | Сервер | Сокет | Юнит | Журнал |
|---|---|---|---|---|
| Debian 13 | MariaDB 11.8 | /run/mysqld/mysqld.sock | mariadb | journalctl |
| Debian 12 | MariaDB 10.11 | /run/mysqld/mysqld.sock | mariadb | journalctl |
| Ubuntu 24.04 | MySQL 8.0 или MariaDB 10.11 | /var/run/mysqld/mysqld.sock | mysql или mariadb | /var/log/mysql/error.log |
| Ubuntu 22.04 | MySQL 8.0 или MariaDB 10.6 | /var/run/mysqld/mysqld.sock | mysql или mariadb | /var/log/mysql/error.log |
| AlmaLinux, Rocky, RHEL | MariaDB или MySQL | /var/lib/mysql/mysql.sock | mariadb или mysqld | /var/log/mariadb/mariadb.log |
Два момента отсюда важны. Первое: в Debian нет пакета mysql-server, там по умолчанию идёт MariaDB. Команда apt install mysql-server в Debian завершится ошибкой, а подходящие к ней инструкции из интернета ведут в никуда. Второе: в семействе Red Hat сокет лежит в каталоге данных, а не в /run. Тот, кто переносит приложение с Debian на AlmaLinux и забирает путь с собой, воспроизводит эту ошибку с гарантией.
Отдельный случай на полях: в контейнерах нет ни systemd, ни привычного хостового /run/mysqld. Если база данных работает в контейнере, а приложение рядом с ним, общего сокета не существует вовсе. Там не обойтись без TCP и имени контейнера в качестве хоста.
Как понять, что проблема действительно устранена
systemctl start без сообщения об ошибке ещё не доказательство. Проверяйте в таком порядке:
systemctl is-active mariadb
ss -lx | grep mysql
mysqladmin ping
mysql -e "SELECT VERSION(), @@socket, @@datadir"
Ответ mysqld is alive от mysqladmin ping и есть настоящий знак качества, потому что он приходит через тот же сокет, которым пользуется и ваше приложение. После этого встречная проверка со стороны прикладного уровня, то есть не от root, а от того пользователя, под которым работает веб-сервер:
sudo -u www-data mysql -u ваш_пользователь -p ваша_база -e "SELECT 1"
И напоследок проверка перезагрузкой. Пугающе большая часть ошибок с сокетом возвращается после следующего reboot, потому что починка действовала только до перезагрузки (каталог создан вручную, символьная ссылка в /tmp, служба не включена в автозапуск). Поэтому:
systemctl enable mariadb
systemctl is-enabled mariadb
Если есть возможность, перезагрузите сервер полностью один раз и повторите четыре проверочные команды. На root-сервере KernelHost это занимает неполную минуту и избавляет вас от повторения той же ошибки в три часа ночи.
Когда что-то идёт не так уже при починке
Три ситуации, в которых люди застревают регулярно.
После изменения конфигурации сервер вообще перестал запускаться. Опечатка в .cnf ведёт к немедленному прерыванию, часто с сообщением unknown variable. Синтаксис можно проверить, не запуская службу, но команда для этого зависит от сервера:
mysqld --validate-config --user=mysql
mariadbd --help --verbose | head -40
Первая строка относится исключительно к MySQL 8. --validate-config — это чисто опция MySQL, и ни в одной версии MariaDB её нет, проверено с 10.5 по 11.8. MariaDB отвечает вместо этого [ERROR] mysqld: unknown option '--validate-config' и следом [ERROR] Aborting, а в семействе Red Hat это сообщение не появляется даже в терминале, оно попадает только в журнал ошибок: команда выглядит там совершенно немой. И --user=mysql тоже обязателен, а не украшение, ведь при вызове от root MySQL 8 прерывается ещё раньше с сообщением Please consult the Knowledge Base to find out how to run mysqld as root!. Для MariaDB аналога --validate-config не существует. Там вторая строка показывает, какие опции сервер вообще знает, а my_print_defaults mysqld mariadbd показывает, что он на самом деле вычитывает из ваших файлов.
Перед каждым изменением сохраняйте копию, тогда обратный путь сводится к одному cp. Кроме того, следите за тем, в какой файл вы пишете: в Debian и Ubuntu файлы в conf.d читаются по алфавиту, и более поздняя запись перекрывает более раннюю.
Вы больше не можете войти как root. У MariaDB в Debian и Ubuntu для root@localhost по умолчанию задана аутентификация через unix_socket. Это значит: sudo mysql работает без пароля, а mysql -u root -p от имени обычного пользователя нет, причём с ошибкой ERROR 1698 (28000): Access denied for user 'root'@'localhost'. Это не проблема сокета, а задуманное поведение.
Вы удалили файл сокета, пока сервер работал. Процесс продолжает работать, держит удалённый inode и по этому пути больше недоступен. Создать файл заново вручную не получится: сокет возникает только через bind() самого процесса. Здесь поможет только аккуратный перезапуск службы. Пока он ещё не сделан, до сервера можно добраться по TCP с помощью --protocol=TCP, если не задан skip-networking. Используйте это окно, чтобы снять дамп важнейших баз данных, прежде чем перезапускать.
Последнее замечание о порядке действий: никогда не меняйте несколько вещей одновременно. Сначала состояние службы, потом сверка путей, потом права. Тот, кто параллельно правит my.cnf, php.ini и права на файлы, потом не знает, что именно помогло, и в следующий раз начинает всё с нуля. Если вы настраиваете систему с чистого листа и хотите избежать таких ловушек с самого начала, поможет Чек-лист по настройке нового root-сервера, а для полного стека базы данных с веб-интерфейсом статья Установка Apache, PHP, MySQL и phpMyAdmin на Debian.
Частые вопросы
Что означает число в скобках в конце сообщения об ошибке?
Почему 127.0.0.1 работает, а localhost нет?
Можно ли просто везде перейти на 127.0.0.1?
Где искать журнал ошибок, если /var/log/mysql/error.log не существует?
Почему путь к сокету на AlmaLinux не такой, как на Debian?
Можно ли удалять файл mysqld.sock?
Сервер после перезагрузки больше не запускается, хотя раньше работал. В чём причина?
2026 KernelHost GmbH. Все права защищены. Эта инструкция охраняется авторским правом. Публикация на других сайтах, в том числе частично или в изменённом виде, без нашего письменного согласия не разрешается. Цитирование с указанием источника и активной ссылкой мы приветствуем.

