diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,8 @@
+## 0.2.5.0 (2020-06-15)
+
+ * Bugfix: when reporting counter values to statsd, send only the
+   increments ([#23](https://github.com/tibbe/ekg-statsd/pull/23)).
+
 ## 0.2.4.1 (2020-05-21)
 
  * Sanitize metric names by replacing `:` with `_` to adhere to the StatsD
diff --git a/System/Remote/Monitoring/Statsd.hs b/System/Remote/Monitoring/Statsd.hs
--- a/System/Remote/Monitoring/Statsd.hs
+++ b/System/Remote/Monitoring/Statsd.hs
@@ -28,11 +28,13 @@
     ) where
 
 import Control.Concurrent (ThreadId, myThreadId, threadDelay, throwTo)
+import Control.Concurrent.MVar (modifyMVar_, newMVar)
 import Control.Exception (IOException, AsyncException(ThreadKilled), catch, fromException)
-import Control.Monad (forM_, when)
+import Control.Monad (foldM, when)
 import qualified Data.ByteString.Char8 as B8
 import qualified Data.HashMap.Strict as M
 import Data.Int (Int64)
+import Data.Maybe (fromMaybe)
 import Data.Monoid ((<>))
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
@@ -142,9 +144,10 @@
 
             return (sendSample, Socket.close socket)
 
+    priorCountsVar <- newMVar M.empty
     let flush = do
           sample <- Metrics.sampleAll store
-          flushSample sample sendSample opts
+          modifyMVar_ priorCountsVar (flushSample sample sendSample opts)
 
     me <- myThreadId
     tid <- forkFinally (loop opts flush) $ \ r -> do
@@ -175,28 +178,40 @@
 time = (round . (* 1000000.0) . toDouble) `fmap` getPOSIXTime
   where toDouble = realToFrac :: Real a => a -> Double
 
-flushSample :: Metrics.Sample -> (B8.ByteString -> IO ()) -> StatsdOptions -> IO ()
-flushSample sample sendSample opts = do
-    forM_ (M.toList sample) $ \ (name, val) ->
-        let fullName = dottedPrefix <> sanitizeName name <> dottedSuffix
-        in  flushMetric fullName val
+flushSample :: Metrics.Sample -> (B8.ByteString -> IO ()) -> StatsdOptions -> M.HashMap T.Text Int64 -> IO (M.HashMap T.Text Int64)
+flushSample sample sendSample opts priorCounts =
+    foldM flushOne priorCounts (M.toList sample)
   where
+    flushOne pc (name, val) =
+      let fullName = dottedPrefix <> sanitizeName name <> dottedSuffix
+      in  flushMetric fullName val pc
+
     sanitizeName = T.map sanitizeChar
     sanitizeChar ':' = '_'
     sanitizeChar c   = c
 
-    flushMetric name (Metrics.Counter n)      = send "|c" name (show n)
-    flushMetric name (Metrics.Gauge n)        = send "|g" name (show n)
-    flushMetric name (Metrics.Distribution d) = sendDistribution name d
-    flushMetric _    (Metrics.Label _)        = return ()
+    flushMetric name (Metrics.Counter n)      pc = sendCounter name n pc
+    flushMetric name (Metrics.Gauge n)        pc = sendGauge name n >> return pc
+    flushMetric name (Metrics.Distribution d) pc = sendDistribution name d pc
+    flushMetric _    (Metrics.Label _)        pc = return pc
 
-    sendDistribution name d = do
-      send "|g" (name <> "." <> "mean"    ) (show $ Distribution.mean     d)
-      send "|g" (name <> "." <> "variance") (show $ Distribution.variance d)
-      send "|c" (name <> "." <> "count"   ) (show $ Distribution.count    d)
-      send "|g" (name <> "." <> "sum"     ) (show $ Distribution.sum      d)
-      send "|g" (name <> "." <> "min"     ) (show $ Distribution.min      d)
-      send "|g" (name <> "." <> "max"     ) (show $ Distribution.max      d)
+    sendGauge name n = send "|g" name (show n)
+
+    -- The statsd convention is to send only the increment
+    -- since the last report, not the total count.
+    sendCounter name n pc = do
+      let old = fromMaybe 0 (M.lookup name pc)
+      send "|c" name (show (n - old))
+      return (M.insert name n pc)
+
+    sendDistribution name d pc = do
+      sendGauge         (name <> "." <> "mean"    ) (Distribution.mean     d)
+      sendGauge         (name <> "." <> "variance") (Distribution.variance d)
+      uc <- sendCounter (name <> "." <> "count"   ) (Distribution.count    d) pc
+      sendGauge         (name <> "." <> "sum"     ) (Distribution.sum      d)
+      sendGauge         (name <> "." <> "min"     ) (Distribution.min      d)
+      sendGauge         (name <> "." <> "max"     ) (Distribution.max      d)
+      return uc
 
     isDebug = debug opts
     dottedPrefix = if T.null (prefix opts) then "" else prefix opts <> "."
diff --git a/ekg-statsd.cabal b/ekg-statsd.cabal
--- a/ekg-statsd.cabal
+++ b/ekg-statsd.cabal
@@ -1,5 +1,5 @@
 name:                ekg-statsd
-version:             0.2.4.1
+version:             0.2.5.0
 synopsis:            Push metrics to statsd
 description:
   This library lets you push system metrics to a statsd server.
@@ -15,7 +15,7 @@
 extra-source-files:  CHANGES.md
 cabal-version:       >=1.10
 tested-with:         GHC == 8.10.1, GHC == 8.8.3, GHC == 8.6.5,
-                     GHC == 8.4.4, GHC == 8.2.2, GHC == 8.0.2,
+                     GHC == 8.4.4,  GHC == 8.2.2, GHC == 8.0.2,
                      GHC == 7.10.3, GHC == 7.8.4, GHC == 7.6.3
 
 library
