Server

chrony vs ntpd: Which Time Daemon and Why

By Prabath Thalangama· October 24, 2026· 3 min read
#linux#ntp#chrony

Introduction

Accurate time matters more than people think: Kerberos fails past 5 minutes of skew, TLS certificate validation gets weird, log correlation across hosts breaks, and distributed databases misbehave. Most distros now ship chrony instead of the reference ntpd. Here's why, and how to operate it.

Why chrony won

ntpd chrony
Cold start to sync minutes seconds
Intermittent network (laptop, flaky WAN) poor — assumes steady polling designed for it
Large offset correction steps, can be disruptive slews smoothly, or steps only when told
Virtual machines / after suspend drifts badly, slow to recover handles clock jumps well
Serve time to others yes yes (allow directive)
Reference-clock / PPS / hardware timestamping mature supported, good

For 99% of servers and all laptops, chrony is the better choice. ntpd still shows up where a very specific reference-clock setup or long institutional history exists.

chrony configuration

/etc/chrony/chrony.conf (Debian) or /etc/chrony.conf (RHEL):

# Upstream sources — pool gives you multiple servers from one line
pool 2.pool.ntp.org iburst
# or specific servers:
server time.cloudflare.com iburst
server time.google.com iburst

# Allow stepping the clock only during the first 3 updates, if off by > 1s
makestep 1.0 3

# Record drift so sync is fast after a reboot
driftfile /var/lib/chrony/chrony.drift

# Serve time to your LAN (optional)
allow 10.0.0.0/8

# Use hardware clock as fallback when offline
rtcsync

iburst sends a rapid initial burst so you sync in seconds, not minutes. makestep is the key tunable: slew (gradually adjust the rate) for small offsets so time never goes backwards; step (jump) only early in life or when drift is too large to slew in reasonable time.

chronyc — the control tool

chronyc tracking       # THE status command: current offset, drift, stratum, last update
chronyc sources -v     # each upstream: reach, offset, jitter; '*' = selected, '+' = candidate
chronyc sourcestats    # per-source frequency/offset error estimates
chronyc ntpdata        # detailed per-source packet info
chronyc makestep       # force an immediate step now (e.g. after a big VM jump)
chronyc -a 'burst 4/4' # extra measurements from a flaky source

Reading chronyc tracking:

Reference ID    : A29FC87B (time.cloudflare.com)
Stratum         : 4
System time     : 0.000012 seconds slow of NTP time
Last offset     : -0.000003 seconds
RMS offset      : 0.000045 seconds
Frequency       : 12.501 ppm slow
Skew            : 0.089 ppm

System time ... slow/fast of NTP time under ~1 ms and RMS offset small = you are synced. Frequency is how far the raw crystal drifts (ppm); chrony corrects for it continuously and stores it in the driftfile.

Verification and troubleshooting

timedatectl                          # "System clock synchronized: yes", "NTP service: active"
chronyc tracking
systemctl status chrony    # or chronyd on RHEL
  • timedatectl says "NTP service: n/a" or "inactive" — chrony isn't running, or systemd-timesyncd is installed and conflicting. Pick one: systemctl disable --now systemd-timesyncd then enable chrony.
  • chronyc sources shows all sources with ? in the reach column / reach 000 — no UDP 123 outbound (firewall), wrong server names, or a captive network. Test: chronyc ntpdata / nc -u -z time.cloudflare.com 123.
  • Offset stuck at seconds and not shrinking — chrony is slewing and it takes time (slew rate is limited), or makestep disallows stepping now. Force it: chronyc makestep.
  • Time correct then jumps after VM migration / host resume — expected; rtcsync + makestep handle it. Add makestep 1.0 -1 (allow stepping any time) on VMs that migrate often, accepting that time can jump.
  • Kerberos / AD auth fails with "clock skew too great" — you're > 300s off. chronyc makestep, then find why it drifted (dead NTP source, blocked 123).
  • This host serves time but clients can't reach it — missing allow directive, or 123/udp not open inbound, or local stratum 10 not set for an offline island.
  • Container has wrong time — containers share the host kernel clock; run chrony on the host, never inside the container. Fix the host.
PrabathStuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.