Avatar ·

Ошибка PDOException SQLSTATE[HY000] [2002] No such file or directory в Laravel

Всем привет! Я новичок в PHP и Laravel, и у меня возникла проблема при попытке подключиться к базе данных MySQL. Когда я запускаю миграцию через php artisan migrate, появляется следующая ошибка:

PDOException: SQLSTATE[HY000] [2002] No such file or directory

Я использую Laravel 10 на macOS. Вот мой файл .env:

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=my_database
DB_USERNAME=root
DB_PASSWORD=secret

MySQL установлен через Homebrew, и сервер запущен — я проверил это через brew services list. Также я могу подключиться к базе через терминал командой mysql -u root -p. Но Laravel почему-то не видит соединение. Что я делаю не так? Пробовал менять DB_HOST на 127.0.0.1, но тогда ошибка меняется на Connection refused. Помогите разобраться, пожалуйста!

<<>>

Причина ошибки и её решение

Ошибка SQLSTATE[HY000] [2002] No such file or directory возникает из-за того, что PHP пытается подключиться к MySQL через Unix-сокет, а не через TCP/IP. В macOS и Linux MySQL по умолчанию может слушать Unix-сокет, расположенный в файловой системе (обычно /tmp/mysql.sock или /var/mysql/mysql.sock). Когда вы указываете DB_HOST=localhost, PHP-драйвер PDO интерпретирует это как попытку подключения через сокет, а не через TCP. Если сокет отсутствует или путь к нему неверный, возникает данная ошибка.

Проверка расположения сокета MySQL

Сначала узнайте, где находится Unix-сокет MySQL. Выполните в терминале:

mysql -u root -p -e "SHOW VARIABLES LIKE 'socket';"

Вы увидите что-то вроде:

+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| socket        | /tmp/mysql.sock |
+---------------+-----------------+

Способ 1: Использовать TCP/IP подключение (рекомендуется)

Самый простой способ — заставить PHP подключаться через TCP/IP, указав DB_HOST=127.0.0.1 вместо localhost. Однако, если вы уже пробовали это и получили Connection refused, значит MySQL не слушает TCP-порт. Чтобы исправить обе проблемы, сделайте следующее:

  1. Откройте конфигурационный файл MySQL (обычно /etc/my.cnf или /usr/local/etc/my.cnf для Homebrew).
  2. Найдите секцию [mysqld] и добавьте или раскомментируйте строку:
[mysqld]
bind-address = 127.0.0.1
port = 3306
  1. Перезапустите MySQL:
brew services restart mysql
  1. Теперь измените .env:
DB_HOST=127.0.0.1
DB_PORT=3306

После этого ошибка должна исчезнуть.

Способ 2: Указать путь к сокету (альтернатива)

Если вы предпочитаете использовать Unix-сокет, добавьте в .env параметр DB_SOCKET:

DB_CONNECTION=mysql
DB_HOST=localhost
DB_SOCKET=/tmp/mysql.sock
DB_DATABASE=my_database
DB_USERNAME=root
DB_PASSWORD=secret

Убедитесь, что путь к сокету совпадает с тем, который вы получили из запроса SHOW VARIABLES LIKE 'socket';.

Способ 3: Настройка через config/database.php

Вы также можете явно настроить подключение в файле config/database.php:

'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', '/tmp/mysql.sock'),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
],

После любых изменений не забудьте очистить кэш конфигурации:

php artisan config:clear

Важные моменты

  • Всегда используйте 127.0.0.1 вместо localhost в продакшене, если не уверены в настройках сокета.
  • После изменения .env перезапустите сервер разработки Laravel (php artisan serve).
  • Проверьте, что MySQL действительно запущен: brew services list или systemctl status mysql.
<<>>

Дополнительное решение: Использование Docker или Homestead

Если вы часто сталкиваетесь с проблемами подключения к MySQL на локальной машине, рассмотрите использование Docker-контейнера для MySQL. Это изолирует среду и устраняет проблемы с путями сокетов. Пример docker-compose.yml:

version: '3'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: my_database
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
volumes:
  mysql_data:

Затем в .env укажите:

DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_database
DB_USERNAME=root
DB_PASSWORD=secret

Docker всегда использует TCP/IP, поэтому ошибки с сокетом не возникнут. Если вы используете Laravel Homestead (Vagrant), проблема часто решается указанием DB_HOST=192.168.10.10 или DB_HOST=127.0.0.1 с портом 33060 (стандартный проброс портов в Homestead).

Быстрая диагностика

Чтобы проверить, какой именно способ подключения использует PHP, выполните скрипт:

<?php
try {
    $pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'secret');
    echo "Connected via socket";
} catch (PDOException $e) {
    echo $e->getMessage();
}
?>

Если ошибка — значит проблема в сокете. Замените localhost на 127.0.0.1 и повторите — если работает, то решение очевидно.