Подключение к MySQL через PDO: частые ошибки новичков
За 15 минут вы поднимете рабочее подключение к MySQL через PDO на PHP 8.x: правильная строка DSN, обработка ошибок и кодировка UTF-8. Разберём ошибки, на которых спотыкаются почти все.

К концу этой инструкции у вас будет рабочий скрипт, который подключается к базе MySQL, отдаёт данные в UTF-8 и падает с понятной ошибкой, а не с белым экраном. Займёт минут пятнадцать, если PHP и MySQL уже установлены. Проверено на PHP 8.1–8.3 и MySQL 8.0.
Что нужно иметь до начала
PDO — это встроенный в PHP слой доступа к базам данных. Он идёт в комплекте, но драйвер для MySQL нужно включить отдельно.
- PHP 8.0 или новее. Проверьте:
php -vв терминале. - Включённое расширение
pdo_mysql. Проверьте:php -m | grep pdo_mysql— в выводе должна быть строкаpdo_mysql. Если её нет, ниже отдельный пункт. - Запущенный сервер MySQL и данные для входа: хост, имя базы, логин, пароль.
- Уже созданная база данных. PDO не создаёт её за вас — если базы нет, подключение упадёт.
Что такое DSN
DSN (Data Source Name) — это строка, в которой вы описываете, к чему подключаетесь: тип драйвера, хост, имя базы и кодировку. Половина ошибок новичков живёт именно в ней.
Шаг 1. Соберите строку подключения
DSN для MySQL выглядит так. Замените значения на свои, пароль и логин пока держите прямо в коде — про вынос в конфиг скажу в конце.
<?php
// PHP 8.x, MySQL 8.0
$host = '127.0.0.1'; // не 'localhost', см. шаг «если не получилось»
$dbname = 'shop';
$user = 'app_user';
$password = 'YOUR_PASSWORD';
// Кодировку задаём прямо в DSN, а не запросом SET NAMES
$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
После этого шага у вас есть переменная $dsn со строкой вида mysql:host=127.0.0.1;dbname=shop;charset=utf8mb4. Проверьте глазами: между параметрами точка с запятой, без пробелов.
Шаг 2. Создайте подключение с правильными опциями
Голый new PDO(...) без опций — источник большинства проблем новичков. Он молча глотает ошибки и возвращает данные не в тех типах. Задайте три опции сразу.
<?php
$options = [
// При ошибке кидать исключение, а не молча возвращать false
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// Возвращать строки как ассоциативные массивы по умолчанию
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
// Использовать настоящие подготовленные выражения на стороне MySQL
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $password, $options);
} catch (PDOException $e) {
// На проде это сообщение логируют, а не показывают пользователю
exit('Не удалось подключиться: ' . $e->getMessage());
}
echo 'Подключение работает';
Запустите файл: php connect.php. Если увидели «Подключение работает» — база на связи. Если вылетело исключение с текстом — это хорошо, значит обработка ошибок настроена, читайте текст и идите в раздел ниже.
Шаг 3. Сделайте первый безопасный запрос
Никогда не подставляйте пользовательские данные в SQL склейкой строк — это прямой путь к SQL-инъекции. PDO для этого и придуман: используйте подготовленные выражения с плейсхолдерами.
<?php
// Именованный плейсхолдер :id вместо подстановки значения в строку
$stmt = $pdo->prepare('SELECT id, name, price FROM products WHERE id = :id');
$stmt->execute(['id' => 42]);
$product = $stmt->fetch(); // вернёт ассоциативный массив или false
if ($product === false) {
echo 'Товар не найден';
} else {
echo $product['name'];
}
Если в консоли появилось имя товара — цепочка от подключения до чтения данных работает целиком.
Опция ATTR_ERRMODE => ERRMODE_EXCEPTION в PHP 8.x включена по умолчанию, но привыкайте задавать её явно: вы не всегда знаете, на какой версии и с какими настройками запустится ваш код.
Если не получилось
Пять ошибок, которые вы почти наверняка встретите. Текст ошибки я привожу так, как его показывает PHP.
SQLSTATE[HY000] [2002] Connection refused
MySQL не отвечает по указанному адресу. Частая причина у новичков — разница между localhost и 127.0.0.1. При localhost PHP пытается соединиться через Unix-сокет, и если путь к сокету не тот, что ждёт MySQL, получаете отказ. Поставьте 127.0.0.1 — это заставит идти по TCP. Проверьте также, что сервер запущен.
SQLSTATE[HY000] [1045] Access denied for user
Неверный логин или пароль, либо у пользователя нет прав на эту базу с этого хоста. В MySQL права привязаны к паре «пользователь + хост»: app_user@localhost и app_user@127.0.0.1 — это формально разные записи. Проверьте, под каким хостом заведён ваш пользователь.
SQLSTATE[HY000] [1049] Unknown database
Базы с таким именем нет. Опечатка в dbname или база просто не создана. Создайте её через клиент MySQL или проверьте точное имя — регистр в именах баз на Linux имеет значение.
could not find driver
Расширение pdo_mysql не подключено. На Debian/Ubuntu ставится пакетом php-mysql (уточните точное имя пакета для вашей версии PHP), после чего перезапустите PHP-FPM или веб-сервер. Проверка — php -m | grep pdo_mysql.
Кракозябры вместо русского текста
Данные читаются, но кириллица превращается в мусор. Причина — забытая кодировка. Убедитесь, что в DSN стоит charset=utf8mb4, а сами таблицы созданы в кодировке utf8mb4. utf8mb4, а не устаревший utf8: последний в MySQL не хранит четырёхбайтные символы, включая эмодзи.
Что такое utf8mb4
В MySQL псевдоним utf8 исторически означает урезанную кодировку максимум в три байта на символ. Полноценный UTF-8 называется utf8mb4. Для новых проектов используйте только его.
Ещё одна частая ловушка: одно подключение на весь скрипт
Новички создают new PDO(...) в каждой функции, где нужен запрос. Каждый вызов — это новое соединение с базой, и под нагрузкой они закончатся. Создайте объект PDO один раз и передавайте его туда, где он нужен. В простом скрипте достаточно объявить его в начале и не плодить копии.
Что делать дальше
Базовое подключение работает — теперь наведите порядок:
- Вынесите логин и пароль из кода в переменные окружения или отдельный файл конфигурации вне корня сайта. Пароль в коде под системой контроля версий рано или поздно утечёт.
- Разберитесь с методами выборки:
fetch()для одной строки,fetchAll()для всех,fetchColumn()для одного значения. - Прочитайте раздел про подготовленные выражения и транзакции в официальной документации PHP — это следующий обязательный шаг для любого, кто пишет в базу.
Кеширование результатов и пул соединений — отдельная тема, в базовом подключении она не нужна.
Субтитры и таймкоды: Расшифровка речи и субтитры по правилам читаемости: 42 знака в строке, две строки, минимум секунда на реплику.
Спросить за 40 ₽Источники: PHP Manual: PDO — PHP Data Objects, PHP Manual: MySQL (PDO) DSN
Частые вопросы
У меня PHP 7.4, всё будет работать так же?
Почему localhost не работает, а 127.0.0.1 работает?
Обязательно ли ставить ATTR_EMULATE_PREPARES в false?
Что делать, если ошибка "could not find driver" не уходит после установки пакета?
Нужно ли вручную закрывать подключение PDO?
Безопасно ли подставлять имя таблицы или столбца через плейсхолдер?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.