diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for wai-extra
 
+## 3.1.4.1
+
+* `Network.Wai.Middleware.Gzip`: Add `Vary: Accept-Encoding` header to responses [#829](https://github.com/yesodweb/wai/pull/829)
+
 ## 3.1.4
 
 * Export `Network.Wai.Middleware.RequestLogger.JSON.requestToJSON` [#827](https://github.com/yesodweb/wai/pull/827)
diff --git a/Network/Wai/Middleware/Gzip.hs b/Network/Wai/Middleware/Gzip.hs
--- a/Network/Wai/Middleware/Gzip.hs
+++ b/Network/Wai/Middleware/Gzip.hs
@@ -29,6 +29,7 @@
 import Data.Default.Class
 import Network.HTTP.Types ( Status, Header, hContentEncoding, hUserAgent
                           , hContentType, hContentLength)
+import Network.HTTP.Types.Header (hVary)
 import System.Directory (doesFileExist, createDirectoryIfMissing)
 import Data.ByteString.Builder (byteString)
 import qualified Data.ByteString.Builder.Extra as Blaze (flush)
@@ -43,7 +44,7 @@
 import Control.Exception (throwIO)
 import qualified System.IO as IO
 import Data.ByteString.Lazy.Internal (defaultChunkSize)
-import Data.Word8 (_semicolon)
+import Data.Word8 (_semicolon, _space, _comma)
 
 data GzipSettings = GzipSettings
     { gzipFiles :: GzipFiles
@@ -93,7 +94,7 @@
 -- Will only be applied based on the 'gzipCheckMime' setting. For default
 -- behavior, see 'defaultCheckMime'.
 gzip :: GzipSettings -> Middleware
-gzip set app env sendResponse = app env $ \res ->
+gzip set app env sendResponse' = app env $ \res ->
     case res of
         ResponseRaw{} -> sendResponse res
         ResponseFile{} | gzipFiles set == GzipIgnore -> sendResponse res
@@ -118,7 +119,9 @@
                     in runAction (res, gzipFiles set)
                 else sendResponse res
   where
-    enc = fromMaybe [] $ (splitCommas . S8.unpack)
+    sendResponse = sendResponse' . mapResponseHeaders (vary:)
+    vary = (hVary, "Accept-Encoding")
+    enc = fromMaybe [] $ splitCommas
                     `fmap` lookup "Accept-Encoding" (requestHeaders env)
     ua = fromMaybe "" $ lookup hUserAgent $ requestHeaders env
     isMSIE6 = "MSIE 6" `S.isInfixOf` ua
@@ -223,8 +226,5 @@
   where
     notLength (x, _) = x /= hContentLength
 
-splitCommas :: String -> [String]
-splitCommas [] = []
-splitCommas x =
-    let (y, z) = break (== ',') x
-     in y : splitCommas (dropWhile (== ' ') $ drop 1 z)
+splitCommas :: S.ByteString -> [S.ByteString]
+splitCommas = map (S.dropWhile (== _space)) . S.split _comma
diff --git a/test/WaiExtraSpec.hs b/test/WaiExtraSpec.hs
--- a/test/WaiExtraSpec.hs
+++ b/test/WaiExtraSpec.hs
@@ -176,12 +176,14 @@
                 { requestHeaders = [("Accept-Encoding", "gzip")]
                 }
     assertHeader "Content-Encoding" "gzip" sres1
+    assertHeader "Vary" "Accept-Encoding" sres1
     liftIO $ decompress (simpleBody sres1) @?= "test"
 
     sres2 <- request defaultRequest
                 { requestHeaders = []
                 }
     assertNoHeader "Content-Encoding" sres2
+    assertHeader "Vary" "Accept-Encoding" sres2
     assertBody "test" sres2
 
 caseDefaultCheckMime :: Assertion
@@ -203,6 +205,7 @@
                     ]
                 }
     assertNoHeader "Content-Encoding" sres1
+    assertHeader "Vary" "Accept-Encoding" sres1
     liftIO $ simpleBody sres1 @?= "test"
 
 caseGzipBypassPre :: Assertion
@@ -211,6 +214,7 @@
                 { requestHeaders = [("Accept-Encoding", "gzip")]
                 }
     assertHeader "Content-Encoding" "gzip" sres1
+    assertHeader "Vary" "Accept-Encoding" sres1
     assertBody "test" sres1 -- the body is not actually compressed
 
 vhostApp1, vhostApp2, vhostApp :: Application
diff --git a/wai-extra.cabal b/wai-extra.cabal
--- a/wai-extra.cabal
+++ b/wai-extra.cabal
@@ -1,5 +1,5 @@
 Name:                wai-extra
-Version:             3.1.4
+Version:             3.1.4.1
 Synopsis:            Provides some basic WAI handlers and middleware.
 description:
   Provides basic WAI handler and middleware functionality:
