Ошибка ERROR 1146 (42S02): Table 'mysql.servers' doesn't exist значит, что в системной базе mysql нет таблицы servers. В ней хранятся описания удалённых серверов для движков FEDERATED и CONNECT. Сервер читает её при старте и при каждом FLUSH PRIVILEGES, поэтому ошибка чаще всего всплывает именно на этой команде.
Почти всегда причина одна: системные таблицы не соответствуют версии сервера. СУБД обновили, а шаг обновления системных таблиц не прошёл. Или каталог данных перенесли с другой версии, или восстановили базу mysql из чужого дампа. Самое частое решение: сделать копию каталога данных и запустить обновление системных таблиц. В MariaDB это mariadb-upgrade --force. В MySQL 8.0.16 и новее — перезапуск сервера с upgrade=FORCE. В старом MySQL до 8.0.16 — mysql_upgrade.
Создавать таблицу руками по SQL из интернета — крайняя мера и только для MariaDB и старого MySQL 5.x. Ниже — порядок действий для MySQL 8.0/8.4 и MariaDB 10.11/11.x на Debian 12/13, Ubuntu 24.04 и AlmaLinux / Rocky Linux 9 и 10.
Когда появляется ошибка
Типичные места:
- при выполнении
FLUSH PRIVILEGES, в том числе в процессе сброса пароля root; - в журнале ошибок при запуске сервера, примерно так:
[ERROR] Can't open and lock privilege tables: Table 'mysql.servers' doesn't exist; - при
CREATE SERVERили работе с FEDERATED-таблицами.
Типичные ситуации, после которых она возникает:
- обновление MySQL или MariaDB на новую major-версию без обновления системных таблиц. Исходная версия этой статьи была написана как раз после обновления MySQL на CentOS: таблица
serversпоявилась в MySQL 5.1, а старый каталог данных остался от 5.0; - перенос
/var/lib/mysqlс сервера, где стояла другая версия; - замена MariaDB на MySQL или обратно поверх того же каталога данных;
- восстановление базы
mysqlиз дампа, снятого на другой версии; - частичное восстановление файлов, ручное удаление файлов из каталога данных, сбой диска.
Шаг 1. Сделайте копию перед любыми действиями
Обновление системных таблиц меняет их структуру. Если что-то пойдёт не так, нужна точка возврата. Самый надёжный вариант — копия каталога данных на остановленном сервере:
sudo systemctl stop mariadb # или mysql / mysqld
sudo cp -a /var/lib/mysql /var/lib/mysql.bak-$(date +%F)
sudo systemctl start mariadb
Проверьте, что на диске хватает места на копию: du -sh /var/lib/mysql и df -h /var/lib. Если сервер работает и пользовательские базы доступны, дополнительно снимите логический дамп:
sudo mysqldump --single-transaction --routines --events --triggers \
--databases site_db1 site_db2 > /root/sites-$(date +%F).sql
В MariaDB та же утилита называется mariadb-dump. Базу mysql в такой дамп не включайте, о причинах ниже.
Шаг 2. Диагностика
Узнайте версию сервера и посмотрите, что есть в системной базе:
sudo mysql -e "SELECT VERSION();"
sudo mysql -e "SHOW TABLES FROM mysql;" | wc -l
sudo mysql -e "SHOW TABLES FROM mysql LIKE 'servers';"
Если пропала одна servers, ситуация простая. Если таблиц в mysql заметно меньше, чем должно быть, или нет user/global_priv, системная база повреждена серьёзно, и путь — восстановление (шаг 5).
Проверьте целостность системных таблиц:
# MariaDB
sudo mariadb-check --check mysql
# MySQL
sudo mysqlcheck --check mysql
Посмотрите, до какой версии системные таблицы обновлялись в последний раз. MariaDB и MySQL до 8.4 пишут её в файл в каталоге данных. MySQL 8.4 ведёт историю в JSON-файле:
sudo cat /var/lib/mysql/mysql_upgrade_info # MariaDB, MySQL до 8.4
sudo cat /var/lib/mysql/mysql_upgrade_history # MySQL 8.4
Если там версия старше текущей, обновление системных таблиц не прошло.
Где искать журнал ошибок:
| Система и СУБД | Журнал |
|---|---|
| Debian 12/13, Ubuntu 24.04, MariaDB | journalctl -u mariadb (по умолчанию пишет в журнал systemd) |
| Ubuntu 24.04, MySQL 8.0 | /var/log/mysql/error.log |
| AlmaLinux / Rocky, MariaDB | /var/log/mariadb/mariadb.log |
| AlmaLinux / Rocky, MySQL из AppStream | /var/log/mysql/mysqld.log |
| MySQL из репозитория Oracle (RPM) | /var/log/mysqld.log |
Точный путь покажет sudo mysql -e "SELECT @@log_error;". Пустое значение или stderr означает, что журнал уходит в systemd.
Шаг 3а. MariaDB: mariadb-upgrade
mariadb-upgrade (раньше mysql_upgrade, старое имя осталось как ссылка) проверяет все таблицы и приводит системную базу mysql к версии сервера. Недостающие системные таблицы он создаёт.
sudo mariadb-upgrade --force
Ключ --force нужен, потому что без него утилита посмотрит в mysql_upgrade_info и может решить, что обновление уже сделано. Под sudo она подключится как root через сокет, пароль не понадобится. Вывод примерно такой:
Phase 1/8: Checking and upgrading mysql database
Processing databases
mysql
mysql.column_stats OK
...
Phase 8/8: Running 'FLUSH PRIVILEGES'
OK
Затем перезапустите сервер и проверьте:
sudo systemctl restart mariadb
sudo mariadb -e "FLUSH PRIVILEGES; SHOW TABLES FROM mysql LIKE 'servers';"
В Debian и Ubuntu служба MariaDB после старта сама запускает /etc/mysql/debian-start, а он вызывает mariadb-upgrade. Поэтому после обычного apt upgrade таблицы обновляются автоматически. Если ошибка всё же есть, значит, этот шаг упал. Причину ищите в journalctl -u mariadb, частая — нехватка места на диске. В AlmaLinux автоматического запуска нет: после смены версии MariaDB mariadb-upgrade нужно выполнить вручную.
Шаг 3б. MySQL 8.0.16 и новее, 8.4: upgrade=FORCE
С MySQL 8.0.16 сервер обновляет системные таблицы сам при запуске. Это управляется опцией upgrade. По умолчанию AUTO: сервер обновляет то, что считает устаревшим. Утилита mysql_upgrade с 8.0.16 объявлена устаревшей, а в 8.4 удалена.
Если сервер решил, что обновлять нечего, а таблицы всё же неправильные, заставьте его проверить всё. Добавьте опцию временно в конфиг. В Ubuntu это /etc/mysql/mysql.conf.d/mysqld.cnf, в AlmaLinux — /etc/my.cnf.d/mysql-server.cnf:
[mysqld]
upgrade = FORCE
sudo systemctl restart mysql # mysqld в AlmaLinux
sudo tail -n 50 /var/log/mysql/error.log
Запуск займёт больше времени: сервер проверяет все объекты во всех базах. После успешного старта уберите строку upgrade = FORCE и перезапустите сервер ещё раз, иначе принудительная проверка будет идти при каждом запуске.
В MySQL 8 системные таблицы хранятся в InnoDB, в общем табличном пространстве mysql.ibd, а их описание — в словаре данных. Пропажа mysql.servers на работающем MySQL 8 — редкость. Обычно это след неудачного обновления с 5.7 или копирования файлов с другой версии. Если upgrade=FORCE не помог, руками таблицы не создавайте, переходите к шагу 5.
Шаг 3в. MySQL до 8.0.16: mysql_upgrade
На старых серверах с MySQL 5.7 или ранним 8.0 обновление делается отдельной утилитой при запущенном сервере:
mysql_upgrade -u root -p
sudo systemctl restart mysqld
Это наследие. MySQL 5.7 давно не поддерживается, и такой сервер стоит планировать к обновлению. Путь обновления только последовательный: 5.7 → 8.0 → 8.4. Перепрыгнуть через версию или откатиться назад на том же каталоге данных нельзя.
Шаг 4. Если upgrade не помог: создать таблицу из штатного скрипта
Этот шаг только для MariaDB и MySQL 5.x. В прежней версии статьи таблицу создавали готовым CREATE TABLE ... ENGINE=MyISAM. Это была структура MySQL 5.1. В MariaDB 10.x и 11.x системные таблицы другие, и копировать чужое определение не нужно. Правильное определение лежит в SQL-скрипте, который поставляется с сервером. Найдите его:
# Debian, Ubuntu
dpkg -L mariadb-server-core mariadb-server 2>/dev/null | grep -i system_tables
# AlmaLinux, Rocky
rpm -qa | grep -i mariadb-server | xargs rpm -ql | grep -i system_tables
Откройте найденный файл, найдите в нём CREATE TABLE IF NOT EXISTS servers и выполните этот оператор целиком в базе mysql. Затем проверьте:
USE mysql;
-- здесь CREATE TABLE IF NOT EXISTS servers (...) из скрипта
FLUSH PRIVILEGES;
Ожидаемый ответ — Query OK, 0 rows affected. После этого всё равно выполните mariadb-upgrade --force: если не хватало одной таблицы, могли быть и другие расхождения.
Шаг 5. Восстановление из бэкапа
Если системная база повреждена сильно, каталог данных перенесли с несовместимой версии или MariaDB подменили на MySQL, чинить на месте бессмысленно. Надёжный путь — чистый каталог данных, затем пользовательские базы и учётки из дампов.
- Остановите сервер и переименуйте старый каталог:
sudo mv /var/lib/mysql /var/lib/mysql.broken. - Создайте новый каталог данных.
# MariaDB
sudo mariadb-install-db --user=mysql --datadir=/var/lib/mysql
# MySQL 8 (root без пароля, задайте его сразу после запуска)
sudo mkdir /var/lib/mysql && sudo chown mysql:mysql /var/lib/mysql
sudo mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql - Запустите службу и восстановите пользовательские базы из логического дампа:
sudo mysql < /root/sites-2026-10-03.sql. - Создайте пользователей заново.
Базу mysql из дампа другой версии не восстанавливайте. Она снова принесёт старую структуру системных таблиц, и вы вернётесь к той же ошибке. Учётки переносят отдельно:
- в MariaDB:
mariadb-dump --system=users > users.sqlна рабочем сервере — получится наборCREATE USERиGRANT; - в MySQL: вывод
SHOW CREATE USERиSHOW GRANTSдля каждого пользователя или дамп через MySQL Shell (util.dumpInstance()с пользователями).
Если дампа нет, а старый каталог хотя бы запускается, снимите дамп пользовательских баз с него. Если и это не выходит, разверните ту же версию СУБД, что была раньше, на временном сервере или в контейнере, подключите копию каталога, снимите дамп и перенесите его. Как переносить сайт с базой целиком, описано в статье Перенос сайта на WordPress из командной строки.
Если таблицы пропали без всякого обновления, проверьте диск. Внезапная порча файлов в /var/lib/mysql — частый симптом сбоя накопителя или файловой системы. Как это сделать, разобрано в статье Проверка и восстановление дисков в Linux.
Перенос datadir: как не получить ту же ошибку
Если каталог данных переносят на другой диск, сервер может не увидеть новый путь или не получить к нему доступ. Тогда в журнале появятся ошибки о системных таблицах, хотя файлы на месте. Порядок переноса:
sudo systemctl stop mariadb
sudo rsync -a /var/lib/mysql/ /data/mysql/
sudo chown -R mysql:mysql /data/mysql
В конфиге сервера в секции [mysqld] укажите datadir = /data/mysql. Дальше — система мандатного доступа:
- Ubuntu с MySQL — AppArmor. Добавьте в
/etc/apparmor.d/tunables/aliasстрокуalias /var/lib/mysql/ -> /data/mysql/,и перезапуститеsudo systemctl restart apparmor. Если профиль MariaDB у вас в режиме enforce (проверьтеsudo aa-status), нужно то же самое. - AlmaLinux / Rocky — SELinux. Не отключайте его. Назначьте каталогу правильный контекст:
sudo semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"
sudo restorecon -Rv /data/mysql
После этого запустите службу и проверьте журнал. Копировать каталог данных между серверами можно только при одинаковой версии СУБД. Между разными версиями переносят дамп.
Симптомы и решения
| Симптом | Причина | Решение |
|---|---|---|
ERROR 1146 ... mysql.servers при FLUSH PRIVILEGES после обновления | Системные таблицы не обновлены | MariaDB: mariadb-upgrade --force; MySQL 8: upgrade=FORCE |
То же после переноса /var/lib/mysql с другого сервера | Каталог данных от другой версии | Обновить таблицы; если не помогло — чистый datadir и дамп |
Нет многих таблиц в mysql, включая user | Сервер смотрит в пустой или чужой каталог, системная база потеряна | Проверить datadir, AppArmor/SELinux; восстановление из бэкапа |
| После замены MariaDB на MySQL (или наоборот) сервер не стартует | Форматы каталогов данных несовместимы | Вернуть прежнюю СУБД, снять дамп, развернуть новую на чистом каталоге |
mariadb-upgrade говорит, что обновление уже сделано | Версия записана в mysql_upgrade_info | Запуск с --force |
mysql_upgrade: command not found на MySQL 8.4 | Утилита удалена | Опция сервера upgrade=FORCE |
| Таблицы пропали без обновлений | Сбой диска или файловой системы | Проверить диск, восстановить из бэкапа |
Частые вопросы
Что хранится в таблице mysql.servers и нужна ли она мне?
В ней описания удалённых серверов для CREATE SERVER, их используют движки FEDERATED и CONNECT. На обычном сервере с сайтами она пустая. Но сервер читает её при запуске и при FLUSH PRIVILEGES, поэтому её отсутствие даёт ошибку, даже если вы её не используете.
Можно ли просто создать таблицу командой из старой статьи?
Для MariaDB это крайняя мера: правильнее взять определение из скрипта, поставляемого с сервером, или дать mariadb-upgrade создать её. Для MySQL 8 нельзя совсем: системные таблицы связаны со словарём данных. Обновление через upgrade=FORCE или восстановление — правильный путь.
Чем mysql_upgrade отличается от автоматического обновления в MySQL 8?
До 8.0.16 после обновления пакетов нужно было вручную запустить mysql_upgrade. С 8.0.16 сервер делает то же самое сам при старте, а поведение задаёт опция upgrade: AUTO, NONE, MINIMAL или FORCE. В 8.4 утилиты mysql_upgrade уже нет.
Ошибка появилась при сбросе пароля root. Что делать?
Сначала почините системные таблицы: запустите сервер в обычном режиме, если к нему есть доступ через сокет, и выполните mariadb-upgrade --force. Потом повторите сброс по инструкции из статьи Сброс пароля root в MySQL 8 и MariaDB.
Нужно ли запускать mariadb-upgrade после обновления Debian 12 до 13?
При переходе Debian 12 на 13 MariaDB обновляется с 10.11 на 11.8. Скрипт debian-start запустит mariadb-upgrade сам при первом старте службы. Проверьте журнал journalctl -u mariadb на ошибки. Перед обновлением системы обязательно сделайте дамп баз.