Ошибка MySQL 2006: Server has gone away означает следующее – клиентом потеряно соединение с сервером MySQL или MariaDB. Причина часто скрывается в большом SQL-запросе или в дампе. Иногда такое происходит из-за перезапуска самого сервера или же во время проблем с самой сетью.

Но данная ошибка сама по себе далеко не всегда означает критические проблемы, такие как повреждение базы данных или поломку MySQL. Чаще всего ситуация намного проще и выглядит так: соединение закрыто, а в это время приложение или клиент пытается продолжить с ним взаимодействие. Как результат отказа от этого взаимодействия и выступает ошибка MySQL 2006: Server has gone away.

Что означает ошибка 2006 и когда она возникает

В этой ситуации код 2006 соответствует клиентской ошибке CR_SERVER_GONE_ERROR — MySQL server has gone away. Ошибка появляется только в том случае, когда клиент не может отправить запрос через существующее соединение с сервером MySQL.

Родственная ошибка 2013 (Lost connection to MySQL server during query) возникает, когда соединение теряется непосредственно во время выполнения запрос. Если говорить о практических ситуациях, то можно выделить несколько распространенных случаев появления кода 2006:

  • в ходе импорта объемного SQL-дампа;

  • во время выполнения большого INSERT, особенно с большим количеством строк;

  • в PHP-приложении после долгого простоя соединения;

  • в CLI-клиенте MySQL;

  • при работе с большими BLOB или другими объемными данными;

  • после перезапуска или падения mysqld/mariadbd;

  • при нестабильном удаленном подключении к базе.

Сложность ситуации в том, что универсальной настройки не существует, которая могла бы закрыть разом все перечисленные проблемы. Поэтому действовать в одной ситуации нужно так – вы сначала определяете причину такого поведения, а уже после подбираете самый эффективный способ устранения проблемы. Ключевая задача на этом этапе – понять, в какой именно момент происходит разрыв соединения.

Причина 1 — истек тайм-аут соединения

Это, пожалуй, самая популярная причина, когда сервер просто закрывает неактивное соединение из-за wait_timeout. С помощью этой переменной устанавливается определенное количество секунд, которое MySQL готов ждать активности от обычного клиентского соединения, прежде чем закрыть его.

В интерактивных подключениях обычно применяется связанная настройка interactive_timeout. Значения устанавливаются глобально и для отдельных сессий. Так если приложением было установлено соединение с MySQL, выполнило запрос, а затем долго ничего не делало, появляется ошибка.

Бывает и так, что соединение остается открытым дольше положенного времени. В таком случае сервер руководствуется установленным правилом, и просто закрывает соединение, когда оно превышает лимит по времени. После закрытия соединения приложение попытается использовать его снова, но результатом этой попытки будет появление MySQL server has gone away.

Поэтому идём в настройки и проверяем:

SHOW VARIABLES LIKE '%timeout%';

Более точечно:

SHOW VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'interactive_timeout';

В MySQL 8.4 "wait_timeout" является динамической переменной, её глобальное значение можно изменить без перезапуска:

SET GLOBAL wait_timeout = 28800;
SET GLOBAL interactive_timeout = 28800;

Есть один нюанс: изменение GLOBAL не переписывает уже установленное значение в существующих сессиях. Новые соединения получат новое глобальное значение.

Для постоянного изменения параметр добавляют в конфигурацию сервера:

[mysqld]
wait_timeout = 28800
interactive_timeout = 28800

После изменения конфигурации MySQL/MariaDB перезапустите сервис.

И тут важно не допускать элементарную ошибку – многие пользователи выставляют максимальное значение. Просто, не задумываясь. Так делать не нужно, поскольку приложение может неправильно управлять соединениями, а увеличенный тайм-аутов будет всего лишь маскировать проблему. Всё это приведет к накоплению долго живущих соединений.

Для решения этой проблемы уместно использовать виртуальный сервер. Вся прелесть ситуации заключается в возможность контролировать конфигурацию MySQL/MariaDB на VPS собственноручно: параметры сервера не зависят от ограничений виртуального хостинга.

Если нужно узнать, какие option files использует именно установленный MySQL, можно проверить:

mysqld --verbose --help 2>/dev/null | grep -A 1 "Default options"

Для MariaDB:

mariadbd --verbose --help 2>/dev/null | grep -A 1 "Default options"

Перейдем к следующей причине.

Причина 2 — превышен max_allowed_packet

Иногда происходит так, что пользователь пытается выполнить импорт дампа или объемного SQL-запроса. Именно в этот момент появляется ошибка. Если это ваш случай, то в первую очередь рекомендуем проверить max_allowed_packet.

Всё дело в том, что этот параметр ограничивает максимальный размер одного пакета данных, который MySQL способен обработать. Проблема особенно актуальна для:

  • больших SQL-дампов;

  • огромных "INSERT";

  • больших "BLOB";

  • длинных строк;

  • массовой вставки большого количества данных одним запросом.

После появления ошибки обязательно проверьте значение командой:

SHOW VARIABLES LIKE 'max_allowed_packet';

В MySQL 8.4 переменная динамическая:

SET GLOBAL max_allowed_packet = 134217728;

Где "134217728" байт — 128 MiB.

В MySQL большой пакет данных – одна из наиболее частых причин появления MySQL 2006: Server has gone away. Что делать в такой ситуации? Увеличить лимит? Как вариант – да, но обязательно учитывайте объем доступной памяти и размер запроса. Запрос должен в полной мере соответствовать этим двум значениям.

Важный момент –  MySQL указывает, что клиент может иметь собственный лимит max_allowed_packet; например, CLI-клиент получает значение через параметр командной строки. Это тот момент, который нужно держать в голове, изменяя глобальное значение.

При импорте дампа используйте:

mysql --max-allowed-packet=128M -u USER -p DATABASE < dump.sql

Во время подключения к удаленному серверу:

mysql -h SERVER_IP --max-allowed-packet=128M -u USER -p DATABASE < dump.sql

В конфигурации сервера параметр задается в секции [mysqld]:

[mysqld]
max_allowed_packet = 128M

Часто пользователи задаются вопросом – “какое значение лучше поставить?”. Универсальной рекомендации тут нет. Ориентируйтесь на конкретно вашу ситуацию. Например, в ваш дамп уместились запросы на 50 МБ, тогда лимит нужно выставить выше этого значения – 60 МБ. Просто ставите лимит выше дампа, но не устанавливаете максимальное значение.

Ошибочно считать, что max_allowed_packet – бесплатная настройка. Чересчур агрессивные значения при большом количестве одновременных подключений к росту потребления памяти. Что касается MariaDB, то здесь max_allowed_packet является динамической глобальной переменной, а максимальное значение – 1 GB. При изменении серверного значения MariaDB рекомендует учитывать значение на стороне клиента.

Причина 3 — процесс MySQL/MariaDB упал или был перезапущен

Если сервер прекратил работу, что привело к падению процесса MySQL/MariaDB, тоже появится ошибка MySQL 2006: Server has gone away. И вот тут нужно тщательно разбираться в причинах такого поведения. Обычно это:

  • нехватка ОЗУ;

  • OOM killer Linux;

  • ошибка самого сервера;

  • повреждение или проблема с конкретным запросом;

  • ручной перезапуск;

  • обновление пакетов;

  • аварийное завершение процесса.

Нет смысла проверять wait_timeout или max_allowed_packet. Первое, что вам нужно сделать в этой ситуации – убедиться, что сервер не падал. Когда сервер падает, старое соединение становится недействительным. Клиент, продолжающий его использовать для установки соединения, будет получать ошибку 2006.

В systemd посмотрите журнал:

sudo journalctl -u mysql --since "1 hour ago"

В MariaDB:

sudo journalctl -u mariadb --since "1 hour ago"

Проверяем сообщения ядра, связанные с нехваткой памяти:

sudo dmesg -T | grep -i -E 'oom|out of memory|killed process'

Или:

sudo journalctl -k | grep -i -E 'oom|out of memory|killed process'

Не будет лишним посмотреть error log MySQL/MariaDB. Многим удается найти причину именно здесь. Так mysqld из-за нехватки памяти просто падает, увеличивая max_allowed_packet, проблема не решается, более того – усугубляется. Сам корень проблемы не в одном параметре, а в недостатке ресурсов под текущую нагрузку.

Для виртуального сервера это важный момент: если серверу постоянно не хватает RAM, логичнее рассматривать тариф с большим объёмом оперативной памяти, чем бесконечно корректировать отдельные параметры MySQL.

Причина 4 — обрыв сети или ограничения инфраструктуры

Во время подключения к базе данных с другого сервера вы рискуете увидеть сообщение MySQL 2006: Server has gone away.

Особенно это актуально для архитектуры вида:

Приложение – интернет – firewall – VPS – MySQL

В этой ситуации MySQL работает нормально, но один из промежуточных компонентов закрывает простаивающее TCP-соединение. Соединение с БД просто может быть прервано одним из следующих участников:

  • firewall;

  • NAT;

  • сетевой сбой;

  • нестабильное удалённое подключение;

  • проблемы с DNS;

  • клиентские read/write timeout.

В документации MySQL отдельно упоминается TCP/IP timeout и сетевые проблемы среди возможных причин потери соединения. Когда база находится на другом сервере, полезно проверить подключение непосредственно с машины приложения:

mysql -h SERVER_IP -u USER -p

Соединение периодически пропадает даже при небольших запросах? Увеличение max_allowed_packet не поможет — нужно искать проблему на сетевом уровне.

Как быстро определить, какая причина у вас

Симптом

Вероятная причина

Что проверить

Ошибка появляется после долгого просто

wait_timeout / interactive_timeout

SHOW VARIABLES LIKE '%timeout%';

Ошибка возникает только на большом дампе

max_allowed_packet

Размер дампа, отдельного SQL-запроса и текущий лимит

Ошибка появляется на большом INSERT

Слишком большой пакет

max_allowed_packet, размер запроса

MySQL внезапно перестал отвечать

Падение/перезапуск сервер

journalctl, error log, uptime

Сервер перезапускается при нагрузке

Нехватка RAM/OOM

dmesg, journalctl -k, мониторинг RAM

Ошибка только при удаленном подключении

Сеть/firewall

TCP-соединение, firewall

После повторного подключения всё работает

Разрыв старой сессии

Тайм-ауты и reconnect-логика

Ошибка возникает постоянно на одном запрос

Проблемный/слишком большой запрос

Логи и размер SQL-запроса

Не лишним будет проверить время работы самого MySQL:

SHOW GLOBAL STATUS LIKE 'Uptime';

Если Uptime неожиданно маленький, сервер недавно перезапускался.

Как предотвратить ошибку в будущем

Универсальной методики нет, в случае появления ошибки нужно разбираться в конкретной ситуации. Но есть простые, однако очень эффективные рекомендации, воспользуйтесь ими, чтобы в будущем снизить риски или полностью исключить вероятность появления MySQL 2006: Server has gone away.

Добавить нормальную реконнект-логику

Приложение не должно считать открытое соединение вечным. После длительного простоя соединение могло быть закрыто сервером или инфраструктурой. В зависимости от используемого драйвера приложение должно уметь обнаружить разрыв и корректно установить новое соединение. MySQL также рекомендует проверять соединение, например через mysql_ping(), если между запросами проходит длительное время.

Контролировать оперативную память

Если MySQL регулярно перезапускается, сначала ищите причину в логах и состоянии RAM. Особенно важно следить за памятью при одновременном использовании:

  • большого InnoDB buffer pool;

  • большого количества соединений;

  • тяжелых запросов;

  • временных таблиц;

  • крупных импортов.

Не завышать max_allowed_packet

Увеличивать параметр нужно под конкретную задачу. Если проблема возникает при импорте дампа, сначала определите размер самых больших запросов. После этого установите разумный запас. 1 GB не является автоматически лучшим значением. Чем выше лимит, тем больше потенциальный объём памяти, который может потребоваться для обработки крупных пакетов. Настройку нужно рассматривать как компромисс между требованиями приложения и доступными ресурсами.

Не увеличивать тайм-ауты без необходимости

Если приложение держит соединения открытыми часами, увеличение wait_timeout может замаскировать проблему управления подключениями. Лучше настроить приложение так, чтобы оно:

  • закрывало ненужные соединения;

  • использовало connection pooling там, где это уместно;

  • корректно восстанавливало соединение;

  • не выполняло огромные операции одним запросом без необходимости.

Заключение

MySQL 2006 Server has gone away не равно поломка базы данных сломалась. В большинстве случаев это следствие конкретного события: сервер закрыл неактивное соединение, запрос оказался слишком большим, MySQL перезапустился либо соединение было потеряно по сети. В таких ситуациях нужно действовать точечно, сперва определяя причину проблемы, а уже после – работать над её устранением.

Оптимальный порядок диагностики выглядит так:

  1. Определить момент ошибки.

  2. Проверить тайм-ауты.

  3. Проверить max_allowed_packet.

  4. Посмотреть, не перезапускался ли MySQL.

  5. Проверить RAM и OOM.

  6. Проверить сеть.

Если выяснилось, что ошибка возникает из-за постоянной нехватки RAM под текущую базу и нагрузку, стоит рассмотреть VPS с большим объемом ресурсов. На виртуальном сервере от Leneex можно самостоятельно управлять конфигурацией MySQL/MariaDB и адаптировать параметры сервера под конкретное приложение, без типичных ограничений виртуального хостинга.