diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 Changelog for tmp-postgres
 
+1.32.0.0
+  #235 Fixed bug where nested calls to cacheAction would deadlock. cacheAction no longer creates parent directories.
+
 1.31.0.3
   #233 Add missing NOINLINE for global lock
 
diff --git a/src/Database/Postgres/Temp/Internal.hs b/src/Database/Postgres/Temp/Internal.hs
--- a/src/Database/Postgres/Temp/Internal.hs
+++ b/src/Database/Postgres/Temp/Internal.hs
@@ -9,7 +9,6 @@
 import Database.Postgres.Temp.Internal.Core
 import Database.Postgres.Temp.Internal.Config
 
-import           Control.Concurrent
 import qualified Control.Concurrent.Async as Async
 import           Control.DeepSeq
 import           Control.Exception
@@ -24,6 +23,7 @@
 import           System.Process
 import           Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
 import           System.Directory
+import           System.Directory.Internal.Prelude
 
 -- | Handle for holding temporary resources, the @postgres@ process handle
 --   and @postgres@ connection information. The 'DB' also includes the
@@ -662,9 +662,6 @@
 -------------------------------------------------------------------------------
 -- cacheAction
 -------------------------------------------------------------------------------
-cacheLock :: MVar ()
-cacheLock = unsafePerformIO $ newMVar ()
-{-# NOINLINE cacheLock #-}
 
 {-|
 Check to see if a cached data directory exists.
@@ -684,7 +681,7 @@
 remigrate as long as the migration does not change. See 'withSnapshot' for
 a ephemeral version of taking snapshots.
 
-@since 1.29.0.0
+@since 1.32.0.0
 -}
 cacheAction
   :: FilePath
@@ -698,17 +695,19 @@
   fixCachePath <- fixPath cachePath
   let result = config <> fromFilePathConfig fixCachePath
 
-  withMVar cacheLock $ \_ -> do
-    nonEmpty <- doesFileExist $ fixCachePath <> "/PG_VERSION"
+  -- TODO document the change in behavior
+  preexisting <- try (createDirectory fixCachePath) >>= \case
+    Left e | isAlreadyExistsError e -> pure True
+    Left e -> throwIO e
+    Right () -> pure False
 
-    if nonEmpty then pure $ pure result else fmap join $ withConfig config $ \db -> do
-      action db
-      -- TODO see if parallel is better
-      throwIfNotSuccess id =<< stopPostgresGracefully db
-      createDirectoryIfMissing True fixCachePath
+  if preexisting then pure $ pure result else fmap join $ withConfig config $ \db -> do
+    -- TODO see if parallel is better
+    action db `onException` removeDirectoryRecursive fixCachePath
+    throwIfNotSuccess id =<< stopPostgresGracefully db
 
-      let snapshotCopyCmd = cpFlags <>
-            toDataDirectory db <> "/* " <> fixCachePath
-      system snapshotCopyCmd >>= \case
-        ExitSuccess -> pure $ pure result
-        x -> pure $ Left $ SnapshotCopyFailed snapshotCopyCmd x
+    let snapshotCopyCmd = cpFlags <>
+          toDataDirectory db <> "/* " <> fixCachePath
+    system snapshotCopyCmd >>= \case
+      ExitSuccess -> pure $ pure result
+      x -> pure $ Left $ SnapshotCopyFailed snapshotCopyCmd x
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -632,7 +632,6 @@
 
   it "works if two threads try to create a cache at the same time" $ do
     withTempDirectory "/tmp" "tmp-postgres-parallel-cache-test" $ \dirPath -> do
-      -- let dirPath = "/tmp/tmp-postgres-parallel-cache-test-1"
       withDbCache $ \cacheInfo -> do
         lock <- newEmptyMVar
         let
@@ -644,6 +643,20 @@
           theCacheAction = cacheAction dirPath waitIfSecond theConfig
         res <- Async.replicateConcurrently 3 theCacheAction
         if all isRight res then pure () else fail "Failed to create caches concurrently"
+
+  it "nested calls don't deadlock" $ do
+    withTempDirectory "/tmp" "tmp-postgres-cache-action" $ \cachePath -> do
+      let
+        action _ = do
+          let differentCachePath = cachePath <> "/cached1"
+          cacheAction differentCachePath (const $ pure ()) defaultConfig >>= \case
+            Left err -> fail $ "Second call should succeed but failed with " <> show err
+            Right _ -> pure ()
+        theFinalCachePath = cachePath <> "/cached"
+
+      cacheAction theFinalCachePath action defaultConfig >>= \case
+        Left err -> fail $ "First call should succeed but failed with " <> show err
+        Right _ -> pure ()
 
 spec :: Spec
 spec = do
diff --git a/tmp-postgres.cabal b/tmp-postgres.cabal
--- a/tmp-postgres.cabal
+++ b/tmp-postgres.cabal
@@ -1,5 +1,5 @@
 name:                tmp-postgres
-version:             1.31.0.3
+version:             1.32.0.0
 synopsis: Start and stop a temporary postgres
 description: Start and stop a temporary postgres. See README.md
 homepage:            https://github.com/jfischoff/tmp-postgres#readme
