The clock drift scenario
You wake up to a broken CI pipeline. The build server rejected a TLS certificate because the system clock drifted three minutes forward. Or your laptop wakes from suspend and suddenly thinks it is 2019. Time drift is invisible until it breaks authentication, ruins log correlation, or causes scheduled tasks to fire twice. Fedora ships with chrony to handle this, but the default configuration assumes a physical desktop with a steady internet connection. When you are running a headless server, a virtual machine, or a machine behind a restrictive firewall, the defaults need adjustment.
What is actually happening
Network Time Protocol does not just ask a server for the current time. It measures round-trip delay, calculates offset, and gradually adjusts the system clock to avoid sudden jumps. A sudden jump breaks databases, corrupts file timestamps, and drops active connections. chrony handles this by slewing the clock. It speeds up or slows down the system frequency slightly until the offset is small enough to step safely. It also predicts drift when the network goes down. The daemon records how fast your hardware clock runs compared to real time, stores that rate in a drift file, and uses it to keep time accurate for days without an NTP source.
Traditional NTP daemons struggle with intermittent connections. They assume a constant stream of packets and often give up when latency spikes. chrony was designed for exactly the opposite environment. It works well on machines that sleep, on virtual machines that pause, and on networks that drop packets. The algorithm weighs recent samples more heavily and ignores outliers automatically. You do not need to tune smoothing constants. The defaults are calibrated for modern hardware.
Check the hardware clock before you blame the network. A failing CMOS battery or a misconfigured BIOS RTC will force chrony to fight a losing battle. Reboot before you debug. Half the time the symptom is gone.
The configuration workflow
Fedora includes chrony by default on Workstation and Server spins. If you are using a minimal base or you accidentally removed it, install it explicitly. The package provides both the daemon and the chronyc client utility.
Here is how to ensure the service is installed, enabled, and allowed through the firewall.
sudo dnf install -y chrony # Guarantees the daemon and chronyc client are present
sudo systemctl enable --now chronyd # Registers the service for boot and starts it immediately
sudo firewall-cmd --add-service=ntp --permanent # Opens UDP port 123 in the persistent firewall rules
sudo firewall-cmd --reload # Applies the persistent rule to the active runtime firewall
firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge.
The main configuration file lives at /etc/chrony.conf. Do not edit the template in /usr/lib/chrony/chrony.conf. Files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/.
Here is how to configure the pool servers, drift tracking, and logging behavior.
# /etc/chrony.conf
# Use the Fedora NTP pool as the primary time source
pool 2.fedora.pool.ntp.org iburst maxsources 4
# Record the system clock drift rate for offline accuracy
driftfile /var/lib/chrony/drift
# Allow local clients to query this machine if it becomes a time server
local stratum 10
# Enable detailed logging for measurements and tracking history
logdir /var/log/chrony
log measurements statistics tracking
The iburst option sends a burst of eight packets on startup. This forces rapid synchronization instead of waiting for the normal polling interval. The maxsources 4 directive limits how many peers chrony will track from the pool. This prevents the daemon from overwhelming a single DNS round-robin entry. The local stratum 10 line makes the machine act as a fallback time source for other machines on the same LAN. It only activates when chrony loses contact with all upstream servers.
Restart the daemon after editing the config. Chrony does not hot-reload pool changes without a restart.
Verify synchronization
You need to confirm that chrony has locked onto a source and that the offset is within acceptable bounds. The chronyc utility provides two primary views. One shows the current tracking state. The other lists all configured peers and their sync status.
Here is how to check the active synchronization state and peer list.
chronyc tracking # Displays current offset, frequency adjustment, and reference source
chronyc sources -v # Lists all configured peers with sync state markers
The output will look similar to this:
210 Number of sources = 4
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* 203.0.113.10 2 6 377 12 +42us[ +51us] +/- 12ms
^+ 198.51.100.20 2 6 377 11 +110us[+119us] +/- 15ms
^- 192.0.2.50 3 6 377 10 +2.1ms[+2.1ms] +/- 45ms
^? 198.51.100.30 0 6 0 - +0ns[ +0ns] +/- 0ns
The * marker means chrony is currently synchronized to that source. The + marker means the source is acceptable and available as a backup. The - marker means the source is rejected due to excessive delay or offset. The ? marker means chrony cannot reach the source at all. If you see ? across the board, check your DNS resolution and firewall rules. If you see * but the offset is larger than 50 milliseconds, your network latency is too high or the upstream server is overloaded.
Check the tracking output before you trust the clock. A large offset means the slew is still working.
Common pitfalls and error patterns
Time synchronization failures rarely come from the daemon itself. They come from environment constraints. Virtual machines are the most common culprit. Hypervisors often pause guest clocks during migration or snapshot operations. When the VM resumes, the clock jumps backward or forward. Chrony detects the jump and steps the clock immediately, but if the jump is larger than the configured threshold, it will refuse to step and log a warning.
Here is how to force chrony to step the clock on large jumps inside a VM.
# Add this line to /etc/chrony.conf for virtualized environments
makestep 1.0 -1 # Allows stepping the clock by any amount on the first update
The 1.0 sets the initial step threshold to one second. The -1 means there is no limit on the number of steps. This is safe for VMs because the hypervisor controls the actual wall clock. Do not use this on physical servers running stateful databases. Sudden steps can break transaction logs.
Another frequent issue is leap second handling. Chrony smears leap seconds by default on modern Fedora kernels. It stretches the second slightly over the preceding day instead of inserting a duplicate second. This prevents applications that cannot handle TIME_UTC from crashing. If you see chronyd: Leap second detected in the logs, the smear is working correctly. Do not disable it unless you are running legacy hardware that requires a hard step.
Firewall misconfigurations also cause silent failures. NTP uses UDP port 123. Many corporate firewalls block outbound UDP entirely. If chronyc sources shows all ? markers, test connectivity manually.
sudo nmap -p 123 --script ntp-info 2.fedora.pool.ntp.org # Verifies UDP 123 is reachable and responds
If the port is closed, you must either whitelist UDP 123 or switch to a different synchronization method. SELinux denials rarely affect chrony because the daemon runs in a confined domain that already has the necessary permissions. If you see avc: denied messages related to chrony, check journalctl -t setroubleshoot for the one-line summary. Read those before disabling SELinux.
Flush the drift file if the clock jumps wildly. Corrupted drift data forces chrony to guess wrong.
When to use chrony versus alternatives
Time synchronization tools differ in complexity and use case. Pick the one that matches your infrastructure constraints.
Use chrony when you need robust timekeeping across network interruptions and variable latency. Use systemd-timesyncd when you are running a lightweight container or a machine that only needs basic synchronization from a single upstream. Use a hardware GPS or PTP clock when you are running financial trading infrastructure or telecom equipment that requires sub-millisecond accuracy. Stick to the default Fedora pool when you are behind a NAT or corporate proxy that blocks direct stratum 1 connections.
Match the time source to the workload. Over-engineering a home lab clock setup wastes cycles.