diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,14 @@
 # ChangeLog for typed-process
 
+## 0.2.12.0
+
+* Add `getPid`, `exitCodeExceptionWithOutput`,
+  `exitCodeExceptionNoOutput`,
+
+* Re-export `System.Process.Pid`
+
+* Thanks to Rebecca Turner @9999years
+
 ## 0.2.11.1
 
 * No user-visible changes
diff --git a/src/System/Process/Typed.hs b/src/System/Process/Typed.hs
--- a/src/System/Process/Typed.hs
+++ b/src/System/Process/Typed.hs
@@ -109,6 +109,9 @@
     , checkExitCode
     , checkExitCodeSTM
 
+      -- ** Process ID
+    , getPid
+
       -- ** Process streams
     , getStdin
     , getStdout
@@ -116,11 +119,14 @@
 
       -- * Exceptions
     , ExitCodeException (..)
+    , exitCodeExceptionWithOutput
+    , exitCodeExceptionNoOutput
     , ByteStringOutputException (..)
 
       -- * Re-exports
     , ExitCode (..)
     , P.StdStream (..)
+    , P.Pid
 
       -- * Unsafe functions
     , unsafeProcessHandle
@@ -634,13 +640,19 @@
     ec <- readTMVar (pExitCode p)
     case ec of
         ExitSuccess -> return ()
-        _ -> throwSTM ExitCodeException
-            { eceExitCode = ec
-            , eceProcessConfig = clearStreams (pConfig p)
-            , eceStdout = L.empty
-            , eceStderr = L.empty
-            }
+        _ -> throwSTM $ exitCodeExceptionNoOutput p ec
 
+-- | Returns the PID (process ID) of a subprocess.
+--
+-- 'Nothing' is returned if the underlying 'P.ProcessHandle' was already closed.
+-- Otherwise a PID is returned that remains valid as long as the handle is
+-- open. The operating system may reuse the PID as soon as the last handle to
+-- the process is closed.
+--
+-- @since 0.2.12.0
+getPid :: Process stdin stdout stderr -> IO (Maybe P.Pid)
+getPid = P.getPid . pHandle
+
 -- | Internal
 clearStreams :: ProcessConfig stdin stdout stderr -> ProcessConfig () () ()
 clearStreams pc = pc
@@ -667,6 +679,18 @@
 getStderr :: Process stdin stdout stderr -> stderr
 getStderr = pStderr
 
+-- | Get a process's configuration.
+--
+-- This is useful for constructing 'ExitCodeException's.
+--
+-- Note that the stdin, stdout, and stderr streams are stored in the 'Process',
+-- not the 'ProcessConfig', so the returned 'ProcessConfig' will always have
+-- empty stdin, stdout, and stderr values.
+--
+-- @since 0.2.12.0
+getProcessConfig :: Process stdin stdout stderr -> ProcessConfig () () ()
+getProcessConfig = pConfig
+
 -- | Take 'System.Process.ProcessHandle' out of the 'Process'.
 -- This method is needed in cases one need to use low level functions
 -- from the @process@ package. Use cases for this method are:
@@ -688,3 +712,45 @@
 -- @since 0.1.1
 unsafeProcessHandle :: Process stdin stdout stderr -> P.ProcessHandle
 unsafeProcessHandle = pHandle
+
+-- | Get an 'ExitCodeException' containing the process's stdout and stderr data.
+--
+-- Note that this will call 'waitExitCode' to block until the process exits, if
+-- it has not exited already.
+--
+-- Unlike 'checkExitCode' and similar, this will return an 'ExitCodeException'
+-- even if the process exits with 'ExitSuccess'.
+--
+-- @since 0.2.12.0
+exitCodeExceptionWithOutput :: MonadIO m
+                            => Process stdin (STM L.ByteString) (STM L.ByteString)
+                            -> m ExitCodeException
+exitCodeExceptionWithOutput process = liftIO $ atomically $ do
+    exitCode <- waitExitCodeSTM process
+    stdout <- getStdout process
+    stderr <- getStderr process
+    pure ExitCodeException
+        { eceExitCode = exitCode
+        , eceProcessConfig = pConfig process
+        , eceStdout = stdout
+        , eceStderr = stderr
+        }
+
+-- | Get an 'ExitCodeException' containing no data other than the exit code and
+-- process config.
+--
+-- Unlike 'checkExitCode' and similar, this will return an 'ExitCodeException'
+-- even if the process exits with 'ExitSuccess'.
+--
+-- @since 0.2.12.0
+exitCodeExceptionNoOutput :: Process stdin stdout stderr
+                          -> ExitCode
+                          -> ExitCodeException
+exitCodeExceptionNoOutput process exitCode =
+    ExitCodeException
+        { eceExitCode = exitCode
+        , eceProcessConfig = pConfig process
+        , eceStdout = L.empty
+        , eceStderr = L.empty
+        }
+
diff --git a/src/System/Process/Typed/Internal.hs b/src/System/Process/Typed/Internal.hs
--- a/src/System/Process/Typed/Internal.hs
+++ b/src/System/Process/Typed/Internal.hs
@@ -590,12 +590,16 @@
 useHandleClose :: Handle -> StreamSpec anyStreamType ()
 useHandleClose h = mkStreamSpec (P.UseHandle h) $ \_ _ -> return ((), hClose h)
 
--- | Exception thrown by 'checkExitCode' in the event of a non-success
--- exit code. Note that 'checkExitCode' is called by other functions
--- as well, like 'runProcess_' or 'readProcess_'.
+-- | Exception thrown by 'System.Process.Typed.checkExitCode' in the event of a
+-- non-success exit code. Note that 'System.Process.Typed.checkExitCode' is
+-- called by other functions as well, like 'System.Process.Typed.runProcess_'
+-- or 'System.Process.Typed.readProcess_'.
 --
 -- Note that several functions that throw an 'ExitCodeException' intentionally do not populate 'eceStdout' or 'eceStderr'.
 -- This prevents unbounded memory usage for large stdout and stderrs.
+--
+-- Functions which do include 'eceStdout' or 'eceStderr' (like
+-- 'System.Process.Typed.readProcess_') state so in their documentation.
 --
 -- @since 0.1.0.0
 data ExitCodeException = ExitCodeException
diff --git a/typed-process.cabal b/typed-process.cabal
--- a/typed-process.cabal
+++ b/typed-process.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.34.4.
+-- This file has been generated from package.yaml by hpack version 0.37.0.
 --
 -- see: https://github.com/sol/hpack
 
 name:           typed-process
-version:        0.2.11.1
+version:        0.2.12.0
 synopsis:       Run external processes, with strong typing of streams
 description:    Please see the tutorial at <https://github.com/fpco/typed-process#readme>
 category:       System
@@ -40,9 +40,9 @@
     , stm
     , transformers
     , unliftio-core
+  default-language: Haskell2010
   if os(windows)
     cpp-options: -DWINDOWS
-  default-language: Haskell2010
 
 test-suite typed-process-test
   type: exitcode-stdio-1.0
