diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,10 @@
 `wai-rate-limit-postgres` uses [PVP Versioning][1].
 The changelog is available [on GitHub][2].
 
+## 0.4.0.0
+
+* Fix encoding bug by changing key type to `bytea` (#5)
+
 ## 0.3.0.0
 
 * Removed unnecessary debug prints
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -8,3 +8,21 @@
 
 Depending on traffic and latency of PostgreSQL, this backend may or may not be appropriate for you.
 
+# Testing locally with Docker
+
+Start a PostgreSQL docker container in a terminal:
+
+
+```shell
+
+$ docker run --name some-postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -it --rm postgres -c log_statement=all
+
+```
+
+Run tests in another terminal with:
+
+```shell
+
+$ export PG_DB_URI=postgres://postgres:postgres@localhost:5432/postgres
+$ cabal test
+```
diff --git a/src/Network/Wai/RateLimit/Postgres.hs b/src/Network/Wai/RateLimit/Postgres.hs
--- a/src/Network/Wai/RateLimit/Postgres.hs
+++ b/src/Network/Wai/RateLimit/Postgres.hs
@@ -46,7 +46,7 @@
             " "
             [ "CREATE TABLE IF NOT EXISTS",
               tableName,
-              "(key VARCHAR PRIMARY KEY,",
+              "(key BYTEA PRIMARY KEY,",
               "usage INT8 NOT NULL,",
               "expires_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP + '1 week'::INTERVAL)"
             ]
@@ -64,7 +64,7 @@
   do
     res <-
       try $
-        PG.query c getUsageQuery (PG.Only key) `catches` sqlHandlers
+        PG.query c getUsageQuery (PG.Only $ PG.Binary key) `catches` sqlHandlers
     return $ do
       rows <- res
       case rows of
@@ -85,7 +85,8 @@
 
 pgBackendIncAndGetUsage :: Pool PG.Connection -> Text -> ByteString -> Integer -> IO (Either PGBackendError Integer)
 pgBackendIncAndGetUsage p tableName key usage = withResource p $ \c -> do
-  res <- try $ PG.query c incAndGetQuery (key, usage) `catches` sqlHandlers
+  res <- try $ PG.query c incAndGetQuery (PG.Binary key, usage) `catches` sqlHandlers
+  print res
   return $ do
     rows <- res
     case rows of
@@ -109,7 +110,7 @@
 
 pgBackendExpireIn :: Pool PG.Connection -> Text -> ByteString -> Integer -> IO (Either PGBackendError ())
 pgBackendExpireIn p tableName key seconds = withResource p $ \c -> do
-  res <- try $ PG.execute c expireInQuery (seconds, key) `catches` sqlHandlers
+  res <- try $ PG.execute c expireInQuery (seconds, PG.Binary key) `catches` sqlHandlers
   return $ do
     count <- res
     if count /= 1
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,8 +1,13 @@
 module Main (main) where
 
 import Control.Concurrent
-import Control.Exception
-import Data.Pool
+  ( ThreadId,
+    forkIO,
+    killThread,
+    threadDelay,
+  )
+import Control.Exception (bracket, throwIO)
+import Data.Pool (Pool, createPool)
 import qualified Database.PostgreSQL.Simple as PG
 import Database.PostgreSQL.Simple.URL (parseDatabaseUrl)
 import Network.HTTP.Client (Manager, defaultManagerSettings, httpLbs, newManager, parseRequest, responseStatus)
@@ -10,12 +15,12 @@
 import qualified Network.Wai as Wai
 import qualified Network.Wai.Handler.Warp as Warp
 import qualified Network.Wai.RateLimit as R
-import Network.Wai.RateLimit.Postgres
+import Network.Wai.RateLimit.Postgres (postgresBackend)
 import qualified Network.Wai.RateLimit.Strategy as R
-import System.Environment.Blank
-import System.IO.Error
-import Test.Tasty
-import Test.Tasty.HUnit
+import System.Environment.Blank (getEnv)
+import System.IO.Error (userError)
+import Test.Tasty (defaultMain)
+import Test.Tasty.HUnit (assertFailure, testCaseSteps)
 
 -- | Example value = "postgres://postgres:postgres@localhost:5432/postgres"
 testPGEnv :: String
@@ -63,7 +68,6 @@
       $ \step ->
         do
           step "Limit excessive requests (1)"
-
           bracket
             (mkTestWaiApp 1 2 "key1" >>= launchApp)
             tearDownApp
@@ -74,7 +78,6 @@
                 assertFailure "Not ratelimited!"
 
           step "Limit excessive requests (2)"
-
           bracket
             (mkTestWaiApp 1 3 "key2" >>= launchApp)
             tearDownApp
@@ -85,7 +88,6 @@
                 assertFailure "Unexpected result!"
 
           step "Allow non-excessive requests"
-
           bracket
             (mkTestWaiApp 1 3 "key3" >>= launchApp)
             tearDownApp
@@ -94,3 +96,30 @@
               rs <- replicateM 3 $ mkReq mgr
               when (rs /= [200, 200, 200]) $
                 assertFailure "Unexpected result!"
+
+          step "Allow excessive requests, slow down and then be allowed"
+          bracket
+            (mkTestWaiApp 1 1 "key4" >>= launchApp)
+            tearDownApp
+            $ \_ -> do
+              mgr <- newManager defaultManagerSettings
+              rs <- replicateM 3 $ mkReq mgr
+              when (rs /= [200, 429, 429]) $
+                assertFailure "Unexpected result!"
+              threadDelay 1_000_000
+              rs2 <- replicateM 1 $ mkReq mgr
+              when (rs2 /= [200]) $
+                assertFailure "Unexpected result!"
+
+          step "Allow keys that are invalid as unicode strings"
+          let invalidUtf8String = "\187" :: ByteString
+          when (isRight (decodeUtf8Strict invalidUtf8String :: Either UnicodeException Text)) $
+            assertFailure "`invalidUtf8String` appears to have a valid UTF8 string"
+          bracket
+            (mkTestWaiApp 1 3 invalidUtf8String >>= launchApp)
+            tearDownApp
+            $ \_ -> do
+              mgr <- newManager defaultManagerSettings
+              rs <- replicateM 3 $ mkReq mgr
+              when (rs /= [200, 200, 200]) $
+                assertFailure $ "Unexpected result: " ++ show rs
diff --git a/wai-rate-limit-postgres.cabal b/wai-rate-limit-postgres.cabal
--- a/wai-rate-limit-postgres.cabal
+++ b/wai-rate-limit-postgres.cabal
@@ -1,6 +1,6 @@
 cabal-version:       3.0
 name:                wai-rate-limit-postgres
-version:             0.3.0.0
+version:             0.4.0.0
 category:            Security, Web, Network
 synopsis:            See README for more info
 description:
