I want to report an issue we’ve encountered with one of the Debian NTP pool servers: 0.debian.pool.ntp.org (84.255.251.205:123).
Our company operates multiple IoT devices, all of which are configured to sync their system time via NTP. However, we’ve observed that some of these devices received completely incorrect timestamps upon their first-time synchronization.
Each row in the table below represents a different device. The first column indicates the actual timestamp when synchronization occurred, while the second column shows the system time after synchronization with the NTP server.
For example, the second to last device in the table logged the following message:
Dec 01 14:29:27 xxx systemd-timesyncd[23348]: Synchronized to time server for the first time 84.255.251.205:123 (0.debian.pool.ntp.org).
However, this log was actually recorded two days ago, meaning the system time was set incorrectly by nearly two months.
I understand that Debian NTP pool servers are not intended for production environments, but I find it surprising that this kind of issue can even occur. I’d like to understand more about how this is possible and whether similar behavior could happen with other pools, such as europe.pool.ntp.org.
(this was flagged by Discourse and I just unflagged it; apologies @johnny141).
The monitoring system has seen twice where this server was wildly inaccurate in January (and some dozen times over the years; out of ~1.3 million checks). Overwhelmingly the server is working well, but it’s also consistently (several times a year) briefly wildly inaccurate.
@apuls, will you email the operator and see if they’d be up for sharing what software/hardware they are running and maybe join us on the forum here to see if we can figure out what’s going on?
To answer the other question: No, changing the time source to europe.pool.ntp.org would not have helped. NTP server operators do not get to choose if their servers are included in some specific vendor zone, nor does the NTP Pool management make such decisions. In other words, this particular server is not limited to serving time only in the “Debian NTP Pool”. This particular server has been listed in the Europe pool as well.
It would be good practice to have a local NTP server, pulling time from multiple sources, and using that to serve time to your local clients. That way, if one upstream server does this, it will be ignored.
It also wastes less bandwidth and server load for the volunteers in the pool. Some of the servers may also rate limit you if there are multiple NTP clients coming from a single IP address, some more aggressively than others, meaning some of the NTP clients might not manage to get the time at all for a while.
As noted, there is no practical difference between the NTP pool and the Debian NTP pool at this time.
More importantly, the fundamental problem you have is not with the pool, but with the timesyncd software that is being used on your IoT devices to set the clock. It is trusting that none of the thousands of volunteer-run and unauthenticated NTP servers in the pool is ever reporting time that is wildly wrong for even a brief time. This generally works, but is very fragile.
If your IoT devices have battery-backed RTC chips and boot with time correct within a few seconds, I suggest disabling timesyncd in favor of a full-fledged NTP client such as ntpd or chrony which will ensure agreement of multiple servers before adjusting the local clock.
If your devices boot with a time of 1970 or 1980, you can still get their clock quickly set early in boot without this single-shot fragility, but it might take a bit of work to understand of your OS’ boot scripts to find a good place to use ntpd -gq 0.debian.pool.ntp.org. 1.debian.pool.ntp.org. 2.debian.pool.ntp.org. 3.debian.pool.ntp.org. or the similar but unmaintained ntpdate 0.debian.pool.ntp.org. 1.debian.pool.ntp.org. 2.debian.pool.ntp.org. 3.debian.pool.ntp.org.
There is undoubtedly a similar chrony invocation available.
The general recommendation is to synchronize using disparate time sources.
I monitor the NTP Pool, including 84.255.251.205, independent of the pool’s distributed monitors. This server has a behavior which might be related to the report.
Usually this server runs at stratum 1, occasionally dropping to stratum 2/3. The reported time accuracy is good. Infrequently though, the server responds indicating stratum 6, reference ID=127.127.1.1 The reported time was in error by days (as much as 92 days) when stratum 6 NTP responses were seen.
The common convention for the Reference ID is that 127.127.1.1 means that the NTP server is synchronizing to host’s clock and is not able to get time from from a local clock (e.g., GNSS) or other NTP servers. I don’t know why the NTP server’s administrator chose stratum 6 for this situation. It’s more common to see stratum 10 returned.
10 is what I recommend for orphan mode, which is much preferable to the local clock driver. 127.127.1.1 reads as the local clock driver to me, which ntpd treats as a zero-delay, minimum-dispersion source of time when no other source is available. It has been deprecated for over a decade, but the message doesn’t seem to reach those promulgating example ntp.conf files. Orphan mode won’t show synchronized if it’s never found a real source, the local driver will. Orphan mode continues to increment the dispersion, the local clock driver does not.
If the server didn’t indicate it’s synchronized, how would the clients synchronize to it? IIRC, with a single ntpd server the main difference between the local driver and orphan configuration is the length of the delay before it activates (4 poll intervals vs 300 seconds?).
In chrony there is the local reference mode enabled by the local directive. It’s not a driver. It has an orphan option for compatibility with the ntpd orphan-specific source selection. The documentation clearly says it makes the server appear synchronized when it’s not. Enabling it on a public server is a bad idea.
Boris here. I maintain this set of public servers at https://chrony.eu. From time to time server went out of sync. This cluster of servers has each own GPS time module and following sources:
GPS0: is RS232 serial line from time module as backup,
GPS1: is USB connection to other time module (3->4; 4->3),
The only possible explanation to me is that there is some startup issue while it synchronizes with other servers. In setup it is set that drops to stratum to 11 while not in sync with any external server, while reading clock from RTC module.
All four servers:
have exact same HW and SW config, except network related parameters,
do not use any system software for time sync except and only chronyd,
are clustered in pairs with keepalived: 3 + 4 and 1 + 2,
cluster pairs are at different locations,
If one fails other will overtake in 50ms.
As non-elegant solution I will implement periodically check of time and react if it out of sync (but is should do automatically). This still does not explain why server was so long in “limbo state”.
Does any of those servers have the local directive in chrony.conf? That needs to be removed to avoid serving clients time from an unsynchronized clock.
I looked at a subset of my 2025 monitoring data for chrony.eu and selected the NTP samples that were in error by over 0.5 seconds. The leap indicator (LI, or alarm) was set to 0 for all samples (with or without errors)
Interestingly when reference ID was 127.127.1.1, the stratum was set to 6, or 8 or 10 or 11.
All error samples had offsets between 42 and 96 days and had reference ID set to 127.127.1.1. Here is a three samples from 2a01:260:4057:4::cc
client time server time difference (days)
1737333053.433599 1733059767.478127636 -49.4593
1738082992.961167 1733059746.562753106 -58.1394
1741356656.843867 1733059753.442727741 -96.029
All dates are given in seconds in the Unix Epoch and correspond to reference ID=127.127.1.1 Look at the server time; it hardly changes even though the dates range from January 2025 to March. Something is wrong with the server’s local clock.
Local clocks, orphan mode, etc should not be used by an NTP pool server. If the server loses touch with time references it should set alarm to 3 and stratum to 0.
Thanks for the explanation. We considered migrating to ntpd, but given our limited experience, it felt like too much work. Updating existing timesyncd commands also seemed risky since we have custom logic for handling long offline periods. In the end, we opted for a simpler solution—setting time.aws.com as the primary time server and time.google.com as a backup.