Ошибка ERROR 1146 (42S02): Table ‘mysql.servers’ doesn’t exist — причины и решение

Ошибка 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, MariaDBjournalctl -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, чинить на месте бессмысленно. Надёжный путь — чистый каталог данных, затем пользовательские базы и учётки из дампов.

  1. Остановите сервер и переименуйте старый каталог: sudo mv /var/lib/mysql /var/lib/mysql.broken.
  2. Создайте новый каталог данных.
    # 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
  3. Запустите службу и восстановите пользовательские базы из логического дампа: sudo mysql < /root/sites-2026-10-03.sql.
  4. Создайте пользователей заново.

Базу 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 на ошибки. Перед обновлением системы обязательно сделайте дамп баз.