DNS_ERROR_RCODE_BADTIME (0X0000233A) – DNS Signature Expired
Your DNS server's clock is wrong, so the DNSSEC signature looks expired. Fix: sync time with NTP, then flush DNS cache.
This error means your DNS server's clock is lying to the DNSSEC validator
If you're seeing 0X0000233A (DNS_ERROR_RCODE_BADTIME), the resolver is rejecting a DNSSEC-signed response because the signature's validity window doesn't overlap with the current time as seen by the server. It's almost never a corrupted DNS record — it's a time sync problem. Let's fix it.
The fix: sync your server's clock with a reliable NTP source
What's actually happening here is that DNSSEC signatures have a strict inception and expiration timestamp. If your server's clock is more than a few minutes off (common with VMs that were snapshotted weeks ago), the resolver sees the signature as either not yet valid or already expired.
- Check the current system time and time zone. Run this in an elevated command prompt:
If thew32tm /query /statusSourcesays Local CMOS Clock or Free-running, you're not syncing to NTP. - Force an immediate sync to a reliable pool:
On a domain controller, you might need to point to the domain hierarchy instead:w32tm /config /manualpeerlist:pool.ntp.org /syncfromflags:manual /reliable:yes /update w32tm /resyncw32tm /resync /rediscover. - Verify the sync worked:
Look forw32tm /query /status /verboseLast Successful Sync TimeandPhase Offset— offset should be under 100 milliseconds. - Flush the DNS cache on the resolver (client or forwarder):
If you're using Windows Server, also runipconfig /flushdns dnscmd /clearcacheClear-DnsServerCachein PowerShell. - Test the query again:
If the error was coming from an authoritative server, runnslookup -type=soa example.com 127.0.0.1dcdiag /test:dns /vto confirm all zones pass validation.
Real-world trigger: I've seen this most often on Amazon EC2 Windows instances that were stopped for 3+ weeks and restarted without updating the clock. The instance's CMOS drifted 22 minutes. After NTP sync, the error vanished instantly.
Why step 3 (flush cache) is mandatory
The reason step 3 works is that the resolver caches the entire DNSSEC chain, including the negative validation result. Even after you fix the clock, the old signature failure sits in the cache with a TTL that might be minutes or hours. Flushing clears that poisoned entry. Without the flush, you'll keep seeing the error even though the root cause is resolved.
Less common variations of the same issue
Variation A: The server time is correct, but the DNSSEC signing key was rotated
If your domain's zone signing key (ZSK) or key signing key (KSK) was rolled over, but the RRSIG records haven't been updated on the authoritative server, the signature's inception date is in the future. This is a misconfiguration on the DNS provider side. Check with dig +dnssec example.com SOA and look at the RRSIG validity times. If the inception timestamp is after now, the provider needs to re-sign the zone.
Variation B: The resolver's clock is correct, but the authoritative server's clock is wrong
Less common, but happens. The authoritative server's signature says it expired 3 days ago because that server's clock was 72 hours ahead when it signed the zone. In this case, fixing the authoritative server's NTP sync and re-signing the zone is the only path. You can't fix this from the client side — you must contact the domain owner.
Variation C: Virtual machine time drift after snapshot restore
Hyper-V, VMware, and KVM snapshots often restore the VM to the exact time of the snapshot. If the snapshot is 6 months old, the DNSSEC signatures issued after that date won't validate. The fix is identical (NTP sync + cache flush), but you also need to disable and re-enable the time synchronization service in the hypervisor: Set-VM -VMName DNS01 -TimeSyncEnabled $false then $true in PowerShell for Hyper-V.
Prevention: lock down time sync permanently
The real fix is to never let the clock drift again. Do this:
- For standalone servers: Set the NTP service to start automatically and use a reliable pool:
w32tm /config /manualpeerlist:"0.pool.ntp.org 1.pool.ntp.org 2.pool.ntp.org 3.pool.ntp.org" /syncfromflags:manual /reliable:yes /update sc config w32time start=auto - For domain-joined servers: The domain hierarchy handles this. Verify with
w32tm /query /configuration— look forTypeshowingNT5DS(domain sync) orNTP. If it saysNoSync, fix it with Group Policy:Computer Configuration > Administrative Templates > System > Windows Time Service > Global Configuration Settings. - In cloud environments (AWS, Azure, GCP): Enable the platform's time sync agent. For AWS, install the Amazon Time Sync service on the instance. For Azure, the Host Time Sync is on by default for Windows — verify with
w32tm /query /status— the source should be something liketime.windows.comor169.254.169.123. - Monitor drift: Set a scheduled task that runs
w32tm /resyncdaily at 3 AM. Log the output. If you see consistent drift over 5 seconds, investigate the NTP source.
One more thing: If you're running Windows Server 2016 or later, the time service uses NTP client by default, but it honors the MaxNegPhaseCorrection and MaxPosPhaseCorrection registry values (default 172800 seconds = 48 hours). That means if the clock is off by more than 48 hours, w32tm /resync will silently refuse to sync. You'll see no error, but the clock stays wrong. In that case, temporarily set a very large correction window:
reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config /v MaxNegPhaseCorrection /t REG_DWORD /d 0xFFFFFFFF /f
reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config /v MaxPosPhaseCorrection /t REG_DWORD /d 0xFFFFFFFF /f
w32tm /resync
# Then set them back to the defaults
reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config /v MaxNegPhaseCorrection /t REG_DWORD /d 0x2A300 /f
reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config /v MaxPosPhaseCorrection /t REG_DWORD /d 0x2A300 /f
That's the whole playbook. Fix the clock, flush the cache, lock down NTP. You won't see 0X0000233A again unless someone re-signs a zone with a wrong timestamp or restores a snapshot from 2019.
Was this solution helpful?