diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for grapesy
 
+## 1.1.1 -- 2025-10-09
+
+* Support `openConnection/closeConnection`
+
 ## 1.1.0 -- 2025-07-17
 
 * User-specified actions on connection/disconnect/reconnect [#280]
diff --git a/grapesy.cabal b/grapesy.cabal
--- a/grapesy.cabal
+++ b/grapesy.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               grapesy
-version:            1.1.0
+version:            1.1.1
 synopsis:           Native Haskell implementation of the gRPC framework
 description:        This is a fully compliant and feature complete native Haskell
                     implementation of gRPC, Google's RPC framework.
diff --git a/src/Network/GRPC/Client.hs b/src/Network/GRPC/Client.hs
--- a/src/Network/GRPC/Client.hs
+++ b/src/Network/GRPC/Client.hs
@@ -4,6 +4,8 @@
   , Server(..)
   , ConnParams(..)
   , withConnection
+  , openConnection
+  , closeConnection
 
     -- ** Reconnection policy
   , ReconnectPolicy(..)
diff --git a/src/Network/GRPC/Client/Connection.hs b/src/Network/GRPC/Client/Connection.hs
--- a/src/Network/GRPC/Client/Connection.hs
+++ b/src/Network/GRPC/Client/Connection.hs
@@ -11,6 +11,8 @@
     -- * Definition
     Connection -- opaque
   , withConnection
+  , openConnection
+  , closeConnection
     -- * Configuration
   , Server(..)
   , ServerValidation(..)
@@ -84,6 +86,9 @@
 
       -- | Connection state
     , connStateVar :: TVar ConnectionState
+
+      -- | Flag for garbage collection.
+    , connOutOfScope :: MVar ()
     }
 
 {-------------------------------------------------------------------------------
@@ -312,7 +317,7 @@
   Open a new connection
 -------------------------------------------------------------------------------}
 
--- | Open connection to the server
+-- | Open a connection to the server.
 --
 -- See 'Network.GRPC.Client.withRPC' for making individual RPCs on the new
 -- connection.
@@ -348,6 +353,22 @@
   -> (Connection -> IO a)
   -> IO a
 withConnection connParams server k = do
+    bracket (openConnection connParams server) closeConnection k
+
+-- | Open a connection to the server.
+--
+-- See 'withConnection' for details.
+--
+-- __Warning:__
+-- Connections hold open resources and must be closed using 'closeConnection'.
+-- To prevent resource and memory leaks due to asynchronous exceptions, it is
+-- recommended to use the bracketed function 'withConnection' whenever
+-- possible, and otherwise run functions that allocate and release a resource
+-- with asynchronous exceptions masked, and ensure that every use allocate
+-- operation is followed by the corresponding release operation even in the
+-- presence of asynchronous exceptions, e.g., using 'bracket'.
+openConnection :: ConnParams -> Server -> IO Connection
+openConnection connParams server = do
     connMetaVar  <- newMVar $ Meta.init (connInitCompression connParams)
     connStateVar <- newTVarIO ConnectionNotReady
 
@@ -360,8 +381,11 @@
     -- when we no longer need the connection (which we indicate by writing to
     -- connOutOfScope).
     void $ forkLabelled "grapesy:stayConnected" $ stayConnectedThread
-    k Connection {connParams, connMetaVar, connStateVar}
-      `finally` putMVar connOutOfScope ()
+    pure Connection {connParams, connMetaVar, connStateVar, connOutOfScope}
+
+-- | Close a connection to the server.
+closeConnection :: Connection -> IO ()
+closeConnection conn = putMVar (connOutOfScope conn) ()
 
 {-------------------------------------------------------------------------------
   Making use of the connection
