diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 1.4.37.3
+
+* Improve error message when request body is too large [#1477](https://github.com/yesodweb/yesod/pull/1477)
+
 ## 1.4.37.2
 
 * Improve error messages for the CSRF checking functions [#1455](https://github.com/yesodweb/yesod/issues/1455)
diff --git a/Yesod/Core/Handler.hs b/Yesod/Core/Handler.hs
--- a/Yesod/Core/Handler.hs
+++ b/Yesod/Core/Handler.hs
@@ -1464,6 +1464,23 @@
 -- The form-based approach has the advantage of working for users with Javascript disabled, while adding the token to the headers with Javascript allows things like submitting JSON or binary data in AJAX requests. Yesod supports checking for a CSRF token in either the POST parameters of the form ('checkCsrfParamNamed'), the headers ('checkCsrfHeaderNamed'), or both options ('checkCsrfHeaderOrParam').
 --
 -- The easiest way to check both sources is to add the 'Yesod.Core.defaultCsrfMiddleware' to your Yesod Middleware.
+--
+-- === Opting-out of CSRF checking for specific routes
+--
+-- (Note: this code is generic to opting out of any Yesod middleware)
+--
+-- @
+-- 'yesodMiddleware' app = do
+--   maybeRoute <- 'getCurrentRoute'
+--   let dontCheckCsrf = case maybeRoute of
+--                         Just HomeR                     -> True  -- Don't check HomeR
+--                         Nothing                        -> True  -- Don't check for 404s
+--                         _                              -> False -- Check other routes
+--
+--   'defaultYesodMiddleware' $ 'defaultCsrfSetCookieMiddleware' $ (if dontCheckCsrf then 'id' else 'defaultCsrfCheckMiddleware') $ app
+-- @
+--
+-- This can also be implemented using the 'csrfCheckMiddleware' function.
 
 -- | The default cookie name for the CSRF token ("XSRF-TOKEN").
 --
diff --git a/Yesod/Core/Internal/Request.hs b/Yesod/Core/Internal/Request.hs
--- a/Yesod/Core/Internal/Request.hs
+++ b/Yesod/Core/Internal/Request.hs
@@ -25,6 +25,7 @@
 import Web.Cookie (parseCookiesText)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as S8
+import qualified Data.ByteString.Lazy.Char8 as LS8
 import Data.Text (Text, pack)
 import Network.HTTP.Types (queryToQueryText, Status (Status))
 import Data.Maybe (fromMaybe, catMaybes)
@@ -60,17 +61,23 @@
             let len = fromIntegral $ S8.length bs
                 remaining' = remaining - len
             if remaining < len
-                then throwIO $ HCWai tooLargeResponse
+                then throwIO $ HCWai $ tooLargeResponse maxLen len
                 else do
                     writeIORef ref remaining'
                     return bs
         }
 
-tooLargeResponse :: W.Response
-tooLargeResponse = W.responseLBS
+tooLargeResponse :: Word64 -> Word64 -> W.Response
+tooLargeResponse maxLen bodyLen = W.responseLBS
     (Status 413 "Too Large")
     [("Content-Type", "text/plain")]
-    "Request body too large to be processed."
+    (L.concat 
+        [ "Request body too large to be processed. The maximum size is "
+        , (LS8.pack (show maxLen))
+        , " bytes; your request body was "
+        , (LS8.pack (show bodyLen))
+        , " bytes. If you're the developer of this site, you can configure the maximum length with the `maximumContentLength` function on the Yesod typeclass."
+        ])
 
 parseWaiRequest :: W.Request
                 -> SessionMap
diff --git a/Yesod/Core/Internal/Run.hs b/Yesod/Core/Internal/Run.hs
--- a/Yesod/Core/Internal/Run.hs
+++ b/Yesod/Core/Internal/Run.hs
@@ -327,7 +327,7 @@
             -> Maybe (Route site)
             -> Application
 yesodRunner handler' YesodRunnerEnv {..} route req sendResponse
-  | Just maxLen <- mmaxLen, KnownLength len <- requestBodyLength req, maxLen < len = sendResponse tooLargeResponse
+  | Just maxLen <- mmaxLen, KnownLength len <- requestBodyLength req, maxLen < len = sendResponse (tooLargeResponse maxLen len)
   | otherwise = do
     let dontSaveSession _ = return []
     (session, saveSession) <- liftIO $
diff --git a/Yesod/Core/Unsafe.hs b/Yesod/Core/Unsafe.hs
--- a/Yesod/Core/Unsafe.hs
+++ b/Yesod/Core/Unsafe.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE CPP #-}
 -- | This is designed to be used as
 --
--- > qualified import Yesod.Core.Unsafe as Unsafe
+-- > import qualified Yesod.Core.Unsafe as Unsafe
 --
 -- This serves as a reminder that the functions are unsafe to use in many situations.
 module Yesod.Core.Unsafe (runFakeHandler, fakeHandlerGetLogger) where
diff --git a/yesod-core.cabal b/yesod-core.cabal
--- a/yesod-core.cabal
+++ b/yesod-core.cabal
@@ -1,5 +1,5 @@
 name:            yesod-core
-version:         1.4.37.2
+version:         1.4.37.3
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
