Почему 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:
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
- Диагностика системного времени на Ubuntu
- Проверка chrony и NTP-синхронизации
- Настройка chrony для точной синхронизации времени
- Проверка MySQL после фикса
- Дополнительные причины и советы
- Источники
- Заключение
Почему 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.
Тестируйте в цикле:
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, но для секунд — бесполезно.
Источники
- MySQL 8.0 Reference Manual - MySQL Server Time Zone Support
- My MySQL server time is not the same as my Server - DBA Stack Exchange
- MySQL Time Different from System Time - Server Fault
- Synchronize time using chrony - Ubuntu Server documentation
- Почему время в MySQL отличается от времени PHP и системы
- Установить часовой пояс MySQL - Stack Overflow на русском
Заключение
В 99% случаев mysql время на 1-2 секунды вперёд UTC — это дрейф системных часов Ubuntu, а chrony синхронизация времени решает проблему за 5 минут: диагностика chronyc tracking, фикс makestep и рестарт. После этого NOW() в MySQL идеально совпадёт с UTC, лаги исчезнут. Регулярно мониторьте NTP — на проде это спасёт от кучи багов в timestamp’ах. Если не помогло, смотрите логи chrony или пиши провайдеру VPS.