Создание пользователя MySQL
-- Создать пользователя для подключения только с localhost
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'StrongPassword123!';
-- Для подключения с любого IP
CREATE USER 'myuser'@'%' IDENTIFIED BY 'StrongPassword123!';
-- Для конкретного IP
CREATE USER 'myuser'@'192.168.1.100' IDENTIFIED BY 'StrongPassword123!';Выдача привилегий (GRANT)
-- Все права на одну базу данных
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';
-- Только чтение
GRANT SELECT ON mydb.* TO 'readonly_user'@'localhost';
-- Чтение + запись
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'localhost';
-- На конкретную таблицу
GRANT SELECT, INSERT ON mydb.orders TO 'reports_user'@'localhost';
-- Суперпользователь (все права на все БД)
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
-- Применить изменения
FLUSH PRIVILEGES;Просмотр привилегий
-- Привилегии конкретного пользователя
SHOW GRANTS FOR 'myuser'@'localhost';
-- Список всех пользователей
SELECT User, Host FROM mysql.user;
-- Текущий пользователь
SHOW GRANTS;Отзыв привилегий (REVOKE)
-- Отозвать конкретные права
REVOKE INSERT, UPDATE, DELETE ON mydb.* FROM 'myuser'@'localhost';
-- Отозвать все права
REVOKE ALL PRIVILEGES ON mydb.* FROM 'myuser'@'localhost';
FLUSH PRIVILEGES;Смена пароля пользователя
-- MySQL 5.7 / MariaDB
SET PASSWORD FOR 'myuser'@'localhost' = PASSWORD('NewPassword456!');
-- MySQL 8.0+
ALTER USER 'myuser'@'localhost' IDENTIFIED BY 'NewPassword456!';
FLUSH PRIVILEGES;Удаление пользователя
DROP USER 'myuser'@'localhost';
FLUSH PRIVILEGES;Создание пользователя для веб-приложения
-- Создать БД и пользователя для нового сайта
CREATE DATABASE myapp_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'SecurePass789!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
CREATE TEMPORARY TABLES, LOCK TABLES ON myapp_db.* TO 'myapp_user'@'localhost';
FLUSH PRIVILEGES;Типичные ошибки прав доступа
| Ошибка | Причина | Решение |
|---|---|---|
| ERROR 1045 (28000): Access denied for user 'app'@'10.0.0.5' | Пользователь создан для 'app'@'localhost', а подключение идёт с другого хоста или IP | Создать отдельную запись пользователя под нужный хост или использовать 'app'@'%' с ограничением по сети через firewall |
| ERROR 1142 (42000): SELECT command denied to user | Пользователю не выдана привилегия SELECT на конкретную таблицу или базу | Проверить SHOW GRANTS FOR 'user'@'host'; и выдать недостающее право |
| ERROR 1396 (HY000): Operation CREATE USER failed | Пользователь с таким именем и хостом уже существует | Использовать CREATE USER IF NOT EXISTS или сначала DROP USER |
Host-маска '%' — типичная ошибка конфигурации
Привилегия для 'user'@'%' разрешает подключение с любого IP-адреса, если сервер MySQL слушает внешние подключения (bind-address не ограничен на 127.0.0.1). Для пользователя веб-приложения, которое всегда работает на том же сервере, что и база данных, единственно правильный вариант — 'user'@'localhost', а не '%': это не даёт подключиться к базе даже при компрометации пароля с внешнего IP, если порт 3306 случайно окажется открыт наружу. Проверка, что порт закрыт снаружи, не заменяет правильную настройку host-маски пользователя — это два независимых уровня защиты.
Когда GRANT ALL — это не решение, а проблема
GRANT ALL PRIVILEGES ON *.* WITH GRANT OPTION имеет смысл только для административной учётной записи, которой пользуется человек, а не для сервисного пользователя приложения. Приложению, которое просто читает и пишет данные, не нужны права DROP, SHUTDOWN, CREATE USER — при SQL-инъекции или утечке пароля из .env злоумышленник получит ровно тот набор прав, что выдан пользователю. Минимальный набор для типичного веб-приложения — SELECT, INSERT, UPDATE, DELETE, плюс CREATE TEMPORARY TABLES и LOCK TABLES, если это использует ORM.
Проверка фактических прав после настройки
# Полный список прав пользователя как их видит сервер
mysql -u root -p -e "SHOW GRANTS FOR 'app_user'@'localhost';"
# Проверить, что пользователь реально не видит другие базы
mysql -u app_user -p -e "SHOW DATABASES;"
# Найти пользователей с опасно широкими правами
mysql -u root -p -e "
SELECT User, Host, Super_priv, Grant_priv, Shutdown_priv
FROM mysql.user
WHERE Super_priv = 'Y' OR Grant_priv = 'Y';"Последний запрос стоит гонять периодически как аудит: если в списке оказался сервисный пользователь приложения, а не только административная учётная запись, это повод пересмотреть его права по принципу минимальных привилегий. Восстановление доступа при утере пароля описано в статье про сброс пароля root.