Yeah, I know the drill. You set NTP, the clock looks good, then you reboot and suddenly it's off by 5 minutes. Or worse, it drifts hours over a week. Happens more often than you'd think.
The Quick Fix
Stop messing with ntpdate or old-school NTP. Ubuntu 22.04 uses systemd-timesyncd by default. The problem isn't NTP itself — it's the hardware clock (RTC) overriding system time at boot. Here's the fix:
- Make sure timesyncd is running:
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd
- Sync the system time first:
sudo timedatectl set-time "$(date +%H:%M:%S)" # if way off, use NTP
sudo systemctl restart systemd-timesyncd
sleep 5
sudo timedatectl status
- Write the system clock to hardware clock:
sudo hwclock --systohc --localtime
That last command is the magic. It writes the current system time (which NTP keeps accurate) to the hardware clock (RTC). After this, the BIOS clock matches NTP time. Reboot won't reset it.
Why This Works
Here's what's happening: Ubuntu 22.04 uses systemd-timesyncd to sync the system clock with NTP servers. It works fine while running. But at boot, the kernel reads the hardware clock (RTC) to set the initial system time. If the RTC is off by minutes or hours — and it often is, because your motherboard battery is weak or the RTC drifted over years — then the system starts with wrong time. Timesyncd then slowly corrects it, but that can take 15-30 minutes. Meanwhile, your logs are wrong, cron jobs fire at odd times, and Kerberos auth breaks.
The hwclock --systohc command forces the RTC to match the current system time. But there's a caveat: you must set --localtime or --utc flag correctly. Most PCs store local time in RTC by default (Windows does this). Ubuntu expects UTC by default. If they mismatch, the clock will always be off by your timezone offset. Check with:
timedatectl | grep "RTC in local TZ"
If it says "yes", good. If "no" and you're dual-booting Windows, set it:
sudo timedatectl set-local-rtc 1 --adjust-system-clock
Less Common Variations
1. Chrony is installed but not configured
Some Ubuntu server images ship with both systemd-timesyncd and chrony. They conflict. Check with sudo systemctl list-units | grep -E 'ntp|chrony'. If both show active, disable one:
sudo systemctl stop chronyd
sudo systemctl disable chronyd
sudo systemctl restart systemd-timesyncd
2. NTP servers unreachable
If your network blocks NTP (port 123 UDP), timesyncd never syncs. Check with sudo timedatectl show-timesync. If it says FallbackNTPServers or Server=0.pool.ntp.org with no status, test connectivity:
sudo systemctl stop systemd-timesyncd
sudo ntpdate -q 0.pool.ntp.org # if this fails, your firewall is blocking
Fix by using a different server or opening port 123.
3. Kernel parameter tweak for drift
If you're on a virtual machine (VMware, KVM), the hypervisor's clock can interfere. Try adding tsc=reliable to kernel boot parameters in /etc/default/grub:
GRUB_CMDLINE_LINUX="tsc=reliable"
sudo update-grub
Then reboot. This forces the kernel to trust the TSC (time stamp counter) more, reducing drift in VMs.
Prevention
To keep this from coming back, add a cron job that runs hwclock --systohc daily. Yes, it's crude, but it works. Or better, use chrony with the rtcsync directive. Here's how:
- Uninstall
systemd-timesyncdand installchrony:
sudo apt remove systemd-timesyncd
sudo apt install chrony
- Edit
/etc/chrony/chrony.confand make sure these lines exist:
pool 0.pool.ntp.org iburst
rtcsync
makestep 1 -1
The rtcsync line tells chrony to automatically sync the hardware clock every 11 minutes. makestep 1 -1 allows instant clock adjustments if drift is over 1 second. This makes your clock rock-solid across reboots.
- Restart chrony:
sudo systemctl restart chrony
sudo chronyc tracking
Check that Last offset stays under 0.1ms. If it's above 10ms after a day, your hardware clock battery is dying. Replace the CR2032 battery on the motherboard.
One last thing: if you're in a container (Docker, LXC), none of this applies. Container clocks inherit from the host. Fix the host clock first.