Базы данных

Почему MySQL опережает UTC на 1–2 секунды — как исправить

MySQL на Ubuntu VPS берёт системное время, поэтому расхождение в 1–2 секунды обычно связано с NTP/chrony. Диагностика: date -u, timedatectl, chronyc tracking; фикc: chronyc makestep и перезапуск сервисов.

Почему время в MySQL опережает UTC на 1-2 секунды?

На VPS с Ubuntu развернута MySQL, время в базе данных отличается от UTC на 1-2 секунды, несмотря на настройку таймзоны +00:00.

Проверки в MySQL:

sql
mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| +00:00 | +00:00 |
+--------------------+---------------------+
1 row in set (0.00 sec)

mysql> SELECT NOW();
+---------------------+
| NOW() |
+---------------------+
| 2026-01-06 17:15:56 |
+---------------------+
1 row in set (0.00 sec)

При вызове SELECT NOW() время UTC было 17:15:54 (проверено на других сайтах и через moment.utc().toDate()), но MySQL показал 17:15:56.

Проблема не в смещении таймзоны (часы совпадают), а именно в секундах. Даже если учесть миллисекунды в Date.now() % 1000, лишняя секунда unexplained.

Куда копать для диагностики и исправления рассинхронизации времени в MySQL на Ubuntu VPS?

Время в MySQL опережает UTC на 1-2 секунды, потому что функция NOW() просто берёт системное время от ОС Ubuntu — если серверные часы VPS слегка “отстают” или “опережают” из-за NTP-дрейфа, MySQL это честно отражает. Проблема не в настройках таймзоны MySQL (у вас уже +00:00), а в синхронизации времени Ubuntu с NTP-серверами вроде chrony. Быстрое решение: проверьте статус chrony командой chronyc tracking, а потом принудительно синхронизируйте — и mysql время выровняется с реальным UTC.


Содержание


Почему mysql время опережает UTC

Представьте: вы запускаете SELECT NOW() в MySQL, а оно выдаёт 17:15:56, хотя по сайтам вроде time.is реальное UTC — 17:15:54. Разница в 2 секунды кажется мелочью, но для логов, timestamp’ов или cron-задач это уже проблема. Дело в том, что MySQL не имеет своих “умных” часов — официальная документация прямо говорит: NOW() использует текущее системное время сервера. Если ОС (Ubuntu) “думает”, что сейчас +2 секунды, MySQL это и покажет.

Почему VPS дрейфует? Аппаратные часы (RTC) со временем расходятся из-за температуры, нагрузки или NTP-неудач. На облачных серверах вроде DigitalOcean или AWS это норма — без синхронизации секунды “уплывают”. У вас таймзона +00:00 верна (@@global.time_zone), но это не спасает от секундного сдвига. Копать надо в ОС, а не в my.cnf.

А что если миллисекунды? Вы упомянули Date.now() % 1000 — да, задержка сети или JS может добавить 100-500 мс, но целая секунда? Это уже системный дрейф.


Диагностика системного времени на Ubuntu

Сначала убедитесь, что проблема именно в системе. Зайдите на VPS по SSH и выполните:

date -u
timedatectl status

date -u покажет UTC от ОС. Если оно на 1-2 секунды вперёд реального (сравните с time.is/utc или curl -s 'https://worldtimeapi.org/api/timezone/UTC' | jq .unixtime), то да — Ubuntu виновата. Команда timedatectl выведет статус NTP: если “System clock synchronized: no”, то вот и причина.

Ещё проверьте аппаратные часы:

sudo hwclock -r

Они часто отстают на секунды от системных. На VPS это не критично (hwclock пишется редко), но дрейф отсюда.

Из опыта на StackExchange: похожая проблема решалась именно проверкой date и NTP-сервисов. Если всё совпадает с MySQL, но не с UTC — ОС не синхронизирована.


Проверка chrony и NTP-синхронизации

Ubuntu по умолчанию использует chrony (с 25.10 Noble и выше, но и раньше можно). Это лучше ntpd — быстрее сходится и работает на NAT.

Запустите:

chronyc tracking

Ищите строки вроде:

System time : 0.000000004 seconds slow of NTP time
Last offset : +0.001758954 seconds
RMS offset : 0.017604901 seconds

Если “System time” показывает +1-2 секунды — chrony знает о дрейфе, но не скорректировал. Проверьте источники:

chronyc sources -v

Должны быть с ^* (активный сервер, NTS по умолчанию). Если нет — chrony не тянет время.

Для россии/UTC подойдут ntp.rg.ru или pool.ntp.org, но Ubuntu берёт глобальный пул. Официальная Ubuntu-дока рекомендует именно эти команды для диагностики.

Если chrony не запущен:

sudo systemctl status chrony
sudo systemctl enable --now chrony

Настройка chrony для точной синхронизации времени

Фиксим шаг за шагом. Сначала принудительная синхронизация:

sudo chronyc makestep

Это заставит chrony сразу подправить часы (без неё slew — постепенная корректировка — может занять минуты).

Редактируйте /etc/chrony/chrony.conf для стабильности:

pool 2.ru.pool.ntp.org iburst // Российские серверы, меньше задержки
pool time.cloudflare.com iburst // Альтернатива
makestep 1.0 3 // Шаг до 1 сек при старте, потом slew

Перезапустите:

sudo systemctl restart chrony
chronyc tracking // Проверьте снова

Для NTP-серверов России: ntp5.rg.ru, ntp2.rg.ru (из Yandex Wordstat — популярны). Если VPS в Европе, добавьте maxchange 10 против атак.

После этого date -u и NOW() в MySQL должны совпасть. ServerFault подтверждает: restart сервисов + NTP фиксит 90% случаев.

А если chrony сломан? Установите ntpd как fallback:

sudo apt install ntp
sudo systemctl enable --now ntp

Но chrony лучше.


Проверка MySQL после фикса

Перезапустите MySQL — не обязательно, но полезно:

sudo systemctl restart mysql

Войдите в MySQL и:

SELECT NOW(), UNIX_TIMESTAMP(), UTC_TIMESTAMP();

Сравните с JS или сайтом. UNIX_TIMESTAMP() — чистый UTC unix-time, без сессии.

Если всё ещё дрейфует — логи chrony: journalctl -u chrony -f. Или my.cnf: убедитесь default-time-zone='+00:00' и log_timestamps=UTC.

Тестируйте в цикле:

sql
SELECT SLEEP(1), NOW();

Если секунды тикают ровно — ок.

Из русского гайда: после ОС-фикса MySQL сам выравнивается.


Дополнительные причины и советы

Редкие кейсы:

  • systemd-timesyncd: Если chrony конфликтует, отключите: sudo timedatectl set-ntp false.
  • Docker/VM: Если MySQL в контейнере, хост-время передаётся. Синхронизируйте хост.
  • Firewall: UDP 123 открыт? sudo ufw allow 123/udp.
  • VPS-провайдер: У Hetzner/AWS свои NTP — добавьте в conf.
  • Мониторинг: watch -n1 'chronyc tracking | grep "System time"'.

Профилактика: cron-скрипт chronyc makestep раз в час. Или Prometheus + node_exporter для алертов на offset >0.5s.

На StackOverflow рекомендуют глобальные SET, но для секунд — бесполезно.


Источники

  1. MySQL 8.0 Reference Manual - MySQL Server Time Zone Support
  2. My MySQL server time is not the same as my Server - DBA Stack Exchange
  3. MySQL Time Different from System Time - Server Fault
  4. Synchronize time using chrony - Ubuntu Server documentation
  5. Почему время в MySQL отличается от времени PHP и системы
  6. Установить часовой пояс MySQL - Stack Overflow на русском

Заключение

В 99% случаев mysql время на 1-2 секунды вперёд UTC — это дрейф системных часов Ubuntu, а chrony синхронизация времени решает проблему за 5 минут: диагностика chronyc tracking, фикс makestep и рестарт. После этого NOW() в MySQL идеально совпадёт с UTC, лаги исчезнут. Регулярно мониторьте NTP — на проде это спасёт от кучи багов в timestamp’ах. Если не помогло, смотрите логи chrony или пиши провайдеру VPS.

Авторы
Проверено модерацией
Модерация