diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+0.5.1
+-----
+
+* Add `toEncodedQueryParam` to `ToHttpApiData` type class. It has default
+  implementation using `toQueryParam`, but may be overriden with more efficient
+  one.
+
 0.5
 ---
 
diff --git a/http-api-data.cabal b/http-api-data.cabal
--- a/http-api-data.cabal
+++ b/http-api-data.cabal
@@ -1,6 +1,6 @@
 cabal-version:   >= 1.10
 name:            http-api-data
-version:         0.5
+version:         0.5.1
 
 synopsis:        Converting to/from HTTP API data like URL pieces, headers and query parameters.
 category:        Web
@@ -31,8 +31,9 @@
   GHC==8.8.4,
   GHC==8.10.7,
   GHC==9.0.2,
-  GHC==9.2.3,
-  GHC==9.4.1
+  GHC==9.2.7,
+  GHC==9.4.4,
+  GHC==9.6.1
 
 flag use-text-show
   description: Use text-show library for efficient ToHttpApiData implementations.
@@ -44,7 +45,7 @@
     include-dirs:   include/
 
     -- GHC bundled
-    build-depends:   base                  >= 4.9      && < 4.17
+    build-depends:   base                  >= 4.9      && < 4.19
                    , bytestring            >= 0.10.8.1 && < 0.12
                    , containers            >= 0.5.7.1  && < 0.7
                    , text                  >= 1.2.3.0  && < 1.3 || >=2.0 && <2.1
@@ -54,7 +55,7 @@
     build-depends:
                      attoparsec            >= 0.13.2.2 && < 0.15
                    , attoparsec-iso8601    >= 1.1.0.0  && < 1.2
-                   , base-compat           >= 0.10.5   && < 0.13
+                   , base-compat           >= 0.10.5   && < 0.14
                    , cookie                >= 0.4.3    && < 0.5
                    , hashable              >= 1.2.7.0  && < 1.5
                    , http-types            >= 0.12.3   && < 0.13
@@ -65,7 +66,7 @@
 
     if flag(use-text-show)
       cpp-options: -DUSE_TEXT_SHOW
-      build-depends: text-show        >= 3.8.2 && <3.10
+      build-depends: text-show        >= 3.8.2 && <3.11
 
     exposed-modules:
       Web.HttpApiData
diff --git a/src/Web/Internal/HttpApiData.hs b/src/Web/Internal/HttpApiData.hs
--- a/src/Web/Internal/HttpApiData.hs
+++ b/src/Web/Internal/HttpApiData.hs
@@ -93,10 +93,10 @@
   toUrlPiece = toQueryParam
 
   -- | Convert to a URL path piece, making sure to encode any special chars.
-  -- The default definition uses 'H.encodePathSegmentsRelative',
+  -- The default definition uses @'H.urlEncodeBuilder' 'False'@
   -- but this may be overriden with a more efficient version.
   toEncodedUrlPiece :: a -> BS.Builder
-  toEncodedUrlPiece = H.encodePathSegmentsRelative . (:[]) . toUrlPiece
+  toEncodedUrlPiece = H.urlEncodeBuilder False . encodeUtf8 . toUrlPiece
 
   -- | Convert to HTTP header value.
   toHeader :: a -> ByteString
@@ -106,6 +106,14 @@
   toQueryParam :: a -> Text
   toQueryParam = toUrlPiece
 
+  -- | Convert to URL query param,
+  -- The default definition uses @'H.urlEncodeBuilder' 'True'@
+  -- but this may be overriden with a more efficient version.
+  --
+  -- @since 0.5.1
+  toEncodedQueryParam :: a -> BS.Builder
+  toEncodedQueryParam = H.urlEncodeBuilder True . encodeUtf8 . toQueryParam
+
 -- | Parse value from HTTP API data.
 --
 -- __WARNING__: Do not derive this using @DeriveAnyClass@ as the generated
@@ -422,12 +430,21 @@
 unsafeToEncodedUrlPiece :: ToHttpApiData a => a -> BS.Builder
 unsafeToEncodedUrlPiece = BS.byteString . encodeUtf8 . toUrlPiece
 
+-- | Convert to a URL-encoded query param using 'toQueryParam'.
+-- /Note/: this function does not check if the result contains unescaped characters!
+--
+-- @since 0.5.1
+unsafeToEncodedQueryParam :: ToHttpApiData a => a -> BS.Builder
+unsafeToEncodedQueryParam = BS.byteString . encodeUtf8 . toQueryParam
+
 -- |
 -- >>> toUrlPiece ()
 -- "_"
 instance ToHttpApiData () where
-  toUrlPiece () = "_"
-  toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  toUrlPiece _          = "_"
+  toHeader _            = "_"
+  toEncodedUrlPiece _   = "_"
+  toEncodedQueryParam _ = "_"
 
 instance ToHttpApiData Char where
   toUrlPiece = T.singleton
@@ -438,29 +455,30 @@
 instance ToHttpApiData Version where
   toUrlPiece = T.pack . showVersion
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  toEncodedQueryParam = unsafeToEncodedQueryParam
 
 instance ToHttpApiData Void    where toUrlPiece = absurd
-instance ToHttpApiData Natural where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
+instance ToHttpApiData Natural where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
 
-instance ToHttpApiData Bool     where toUrlPiece = showTextData; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Ordering where toUrlPiece = showTextData; toEncodedUrlPiece = unsafeToEncodedUrlPiece
+instance ToHttpApiData Bool     where toUrlPiece = showTextData; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Ordering where toUrlPiece = showTextData; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
 
-instance ToHttpApiData Double   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Float    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Int      where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Int8     where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Int16    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Int32    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Int64    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Integer  where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Word     where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Word8    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Word16   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Word32   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
-instance ToHttpApiData Word64   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
+instance ToHttpApiData Double   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Float    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Int      where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Int8     where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Int16    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Int32    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Int64    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Integer  where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Word     where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Word8    where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Word16   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Word32   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
+instance ToHttpApiData Word64   where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
 
 -- | Note: this instance is not polykinded
-instance F.HasResolution a => ToHttpApiData (F.Fixed (a :: Type)) where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
+instance F.HasResolution a => ToHttpApiData (F.Fixed (a :: Type)) where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece; toEncodedQueryParam = unsafeToEncodedQueryParam
 
 -- |
 -- >>> toUrlPiece (fromGregorian 2015 10 03)
@@ -468,6 +486,7 @@
 instance ToHttpApiData Day where
   toUrlPiece = T.pack . show
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  toEncodedQueryParam = unsafeToEncodedQueryParam
 
 timeToUrlPiece :: FormatTime t => String -> t -> Text
 timeToUrlPiece fmt = T.pack . formatTime defaultTimeLocale (iso8601DateFormat (Just fmt))
@@ -478,6 +497,7 @@
 instance ToHttpApiData TimeOfDay where
   toUrlPiece = T.pack . formatTime defaultTimeLocale "%H:%M:%S%Q"
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  -- no toEncodedQueryParam as : is unsafe char.
 
 -- |
 -- >>> toUrlPiece $ LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 21.687)
@@ -485,6 +505,7 @@
 instance ToHttpApiData LocalTime where
   toUrlPiece = timeToUrlPiece "%H:%M:%S%Q"
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  -- no toEncodedQueryParam as : is unsafe char.
 
 -- |
 -- >>> toUrlPiece $ ZonedTime (LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 51.001)) utc
@@ -492,6 +513,7 @@
 instance ToHttpApiData ZonedTime where
   toUrlPiece = timeToUrlPiece "%H:%M:%S%Q%z"
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  -- no toEncodedQueryParam as : is unsafe char.
 
 -- |
 -- >>> toUrlPiece $ UTCTime (fromGregorian 2015 10 03) 864.5
@@ -499,6 +521,7 @@
 instance ToHttpApiData UTCTime where
   toUrlPiece = timeToUrlPiece "%H:%M:%S%QZ"
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  -- no toEncodedQueryParam as : is unsafe char.
 
 -- |
 -- >>> toUrlPiece Monday
@@ -513,8 +536,9 @@
   toUrlPiece Sunday    = "sunday"
 
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  toEncodedQueryParam = unsafeToEncodedQueryParam
 
--- | 
+-- |
 -- >>> toUrlPiece Q4
 -- "q4"
 instance ToHttpApiData QuarterOfYear where
@@ -523,6 +547,9 @@
   toUrlPiece Q3 = "q3"
   toUrlPiece Q4 = "q4"
 
+  toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  toEncodedQueryParam = unsafeToEncodedQueryParam
+
 -- |
 -- >>> import Data.Time.Calendar.Quarter.Compat (Quarter (..))
 -- >>> MkQuarter 8040
@@ -540,6 +567,9 @@
       f Q3 = "q3"
       f Q4 = "q4"
 
+  toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  toEncodedQueryParam = unsafeToEncodedQueryParam
+
 -- |
 -- >>> import Data.Time.Calendar.Month.Compat (Month (..))
 -- >>> MkMonth 24482
@@ -551,8 +581,13 @@
 instance ToHttpApiData Month where
   toUrlPiece = T.pack . formatTime defaultTimeLocale "%Y-%m"
 
+  toEncodedUrlPiece = unsafeToEncodedUrlPiece
+  toEncodedQueryParam = unsafeToEncodedQueryParam
+
 instance ToHttpApiData NominalDiffTime where
   toUrlPiece = toUrlPiece . nominalDiffTimeToSeconds
+
+  toEncodedQueryParam = unsafeToEncodedQueryParam
   toEncodedUrlPiece = unsafeToEncodedUrlPiece
 
 instance ToHttpApiData String   where toUrlPiece = T.pack
@@ -562,46 +597,57 @@
 instance ToHttpApiData All where
   toUrlPiece        = coerce (toUrlPiece :: Bool -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Bool -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: Bool -> BS.Builder)
 
 instance ToHttpApiData Any where
   toUrlPiece        = coerce (toUrlPiece :: Bool -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Bool -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: Bool -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Dual a) where
   toUrlPiece        = coerce (toUrlPiece :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Sum a) where
   toUrlPiece        = coerce (toUrlPiece :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Product a) where
   toUrlPiece        = coerce (toUrlPiece :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (First a) where
   toUrlPiece        = coerce (toUrlPiece :: Maybe a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Maybe a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: Maybe a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Last a) where
   toUrlPiece        = coerce (toUrlPiece :: Maybe a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Maybe a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: Maybe a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Semi.Min a) where
   toUrlPiece        = coerce (toUrlPiece :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Semi.Max a) where
   toUrlPiece        = coerce (toUrlPiece :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Semi.First a) where
   toUrlPiece        = coerce (toUrlPiece :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 instance ToHttpApiData a => ToHttpApiData (Semi.Last a) where
   toUrlPiece        = coerce (toUrlPiece :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 -- |
 -- >>> toUrlPiece (Just "Hello")
@@ -639,6 +685,7 @@
   toHeader          = coerce (toHeader :: a -> ByteString)
   toQueryParam      = coerce (toQueryParam :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece ::  a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 -- | @since 0.4.2
 instance ToHttpApiData a => ToHttpApiData (Const a b) where
@@ -646,6 +693,7 @@
   toHeader          = coerce (toHeader :: a -> ByteString)
   toQueryParam      = coerce (toQueryParam :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece ::  a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 -- | @since 0.4.2
 instance ToHttpApiData a => ToHttpApiData (Identity a) where
@@ -653,6 +701,7 @@
   toHeader          = coerce (toHeader :: a -> ByteString)
   toQueryParam      = coerce (toQueryParam :: a -> Text)
   toEncodedUrlPiece = coerce (toEncodedUrlPiece ::  a -> BS.Builder)
+  toEncodedQueryParam = coerce (toEncodedQueryParam :: a -> BS.Builder)
 
 -- |
 -- >>> parseUrlPiece "_" :: Either Text ()
diff --git a/test/Web/Internal/HttpApiDataSpec.hs b/test/Web/Internal/HttpApiDataSpec.hs
--- a/test/Web/Internal/HttpApiDataSpec.hs
+++ b/test/Web/Internal/HttpApiDataSpec.hs
@@ -46,6 +46,9 @@
 encodedUrlPieceProp :: ToHttpApiData a => a -> Property
 encodedUrlPieceProp x = toLazyByteString (toEncodedUrlPiece (toUrlPiece x)) === toLazyByteString (toEncodedUrlPiece x)
 
+encodedQueryParamProp :: ToHttpApiData a => a -> Property
+encodedQueryParamProp x = toLazyByteString (toEncodedQueryParam (toQueryParam x)) === toLazyByteString (toEncodedQueryParam x)
+
 -- | Check 'ToHttpApiData' and 'FromHttpApiData' compatibility
 checkUrlPiece :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Show a, Arbitrary a) => Proxy a -> String -> Spec
 checkUrlPiece _ = checkUrlPiece' (arbitrary :: Gen a)
@@ -56,6 +59,7 @@
     prop "toQueryParam <=> parseQueryParam" $ forAll gen (toQueryParam <=> parseQueryParam :: a -> Property)
     prop "toHeader <=> parseHeader" $ forAll gen (toHeader <=> parseHeader :: a -> Property)
     prop "toEncodedUrlPiece encodes correctly" $ forAll gen encodedUrlPieceProp
+    prop "toEncodedQueryParam encodes correctly" $ forAll gen encodedQueryParamProp
 
 -- | Check case insensitivity for @parseUrlPiece@.
 checkUrlPieceI :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Arbitrary a) => Proxy a -> String -> Spec
