diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,12 @@
 # ChangeLog for time-manager
 
+## 0.5.1
+
+* A renewed timeout compared nanoseconds with microseconds, so a timeout
+  renewed after its callback had been queued ran at once instead of being
+  rescheduled for the time it had just been given. Wrong since 0.4.0.
+  [#1134](https://github.com/yesodweb/wai/pull/1134)
+
 ## 0.5.0
 
 * BREAKING CHANGE: a `ThreadManager` no longer carries a `T.Manager`.
diff --git a/System/TimeManager.hs b/System/TimeManager.hs
--- a/System/TimeManager.hs
+++ b/System/TimeManager.hs
@@ -276,8 +276,8 @@
                 ifSameKey key $ do
                     lastRenewed <- I.readIORef handleLastRenewed
                     now <- getMonotonicTimeNSec
-                    let diff = fromIntegral $ now - lastRenewed
-                    if diff > handleTimeout
+                    let diff = fromIntegral $ (now - lastRenewed) `div` 1_000
+                    if diff >= handleTimeout
                         -- Valid expiration of the timeout, we run the action
                         then do
                             -- We're going to run the action, so set the state
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -41,6 +41,7 @@
     readIORef,
     writeIORef,
  )
+import GHC.Clock (getMonotonicTimeNSec)
 import GHC.Conc.Sync (
     getUncaughtExceptionHandler,
     setUncaughtExceptionHandler,
@@ -61,6 +62,7 @@
  )
 import System.TimeManager
 import System.TimeManager.Internal
+import qualified System.Timeout as Timeout
 import Test.HUnit (assertBool)
 
 main :: IO ()
@@ -270,6 +272,21 @@
                 pause h
                 resume h
                 timeoutOnlyRanOnce
+
+        it "reschedules an expired callback for the remaining timeout" $ do
+            m <- initialize 1_000_000
+            fired <- newEmptyMVar
+            withHandle m (putMVar fired ()) $ \h -> do
+                threadDelay 500_000
+                -- Model a renewal after GHC has queued the original callback.
+                -- Updating GHC's timer here would remove that stale callback.
+                withLock (handleLock h) $ do
+                    now <- getMonotonicTimeNSec
+                    I.writeIORef (handleLastRenewed h) now
+                Timeout.timeout 750_000 (takeMVar fired)
+                    `shouldReturn` Nothing
+                Timeout.timeout 1_000_000 (takeMVar fired)
+                    `shouldReturn` Just ()
 
         it "resume also works as tickle" $
             testResume resume
diff --git a/time-manager.cabal b/time-manager.cabal
--- a/time-manager.cabal
+++ b/time-manager.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               time-manager
-version:            0.5.0
+version:            0.5.1
 license:            MIT
 license-file:       LICENSE
 maintainer:         kazu@iij.ad.jp
