diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -11,6 +11,7 @@
 #include <sync.h>
 #include <test/util/chainstate.h>
 #include <test/util/setup_common.h>
+#include <timedata.h>
 #include <validation.h>
 #include <validationinterface.h>
 
@@ -170,11 +171,30 @@
 }
 
 struct SnapshotTestSetup : TestChain100Setup {
+    // Run with coinsdb on the filesystem to support, e.g., moving invalidated
+    // chainstate dirs to "*_invalid".
+    //
+    // Note that this means the tests run considerably slower than in-memory DB
+    // tests, but we can't otherwise test this functionality since it relies on
+    // destructive filesystem operations.
+    SnapshotTestSetup()
+        : TestChain100Setup{
+              {},
+              {},
+              /*coins_db_in_memory=*/false,
+              /*block_tree_db_in_memory=*/false,
+          } {}
+
     std::tuple<Chainstate *, Chainstate *> SetupSnapshot() {
         ChainstateManager &chainman = *Assert(m_node.chainman);
 
         BOOST_CHECK(!chainman.IsSnapshotActive());
-        WITH_LOCK(::cs_main, BOOST_CHECK(!chainman.IsSnapshotValidated()));
+
+        {
+            LOCK(::cs_main);
+            BOOST_CHECK(!chainman.IsSnapshotValidated());
+            BOOST_CHECK(!node::FindSnapshotChainstateDir());
+        }
 
         size_t initial_size;
         size_t initial_total_coins{100};
@@ -223,6 +243,9 @@
                 auto_infile >> outpoint;
                 auto_infile >> coin;
             }));
+
+        BOOST_CHECK(!node::FindSnapshotChainstateDir());
+
         BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
             this, [](AutoFile &auto_infile, SnapshotMetadata &metadata) {
                 // Coins count is larger than coins in file
@@ -245,6 +268,7 @@
             }));
 
         BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(this));
+        BOOST_CHECK(fs::exists(*node::FindSnapshotChainstateDir()));
 
         // Ensure our active chain is the snapshot chainstate.
         BOOST_CHECK(
@@ -258,18 +282,18 @@
         {
             LOCK(::cs_main);
 
+            fs::path found = *node::FindSnapshotChainstateDir();
+
             // Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
-            BOOST_CHECK_EQUAL(
-                *node::ReadSnapshotBaseBlockhash(m_args.GetDataDirNet() /
-                                                 "chainstate_snapshot"),
-                *chainman.SnapshotBlockhash());
+            BOOST_CHECK_EQUAL(*node::ReadSnapshotBaseBlockhash(found),
+                              *chainman.SnapshotBlockhash());
 
             // Ensure that the genesis block was not marked assumed-valid.
             BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid());
         }
 
-        const AssumeutxoData &au_data =
-            *ExpectedAssumeutxo(snapshot_height, ::Params());
+        const AssumeutxoData &au_data = *ExpectedAssumeutxo(
+            snapshot_height, ::GetConfig().GetChainParams());
         const CBlockIndex *tip =
             WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
 
@@ -351,6 +375,29 @@
             loaded_snapshot_blockhash);
         return std::make_tuple(&validation_chainstate, &snapshot_chainstate);
     }
+
+    //! Simulate a restart of the node by flushing all state to disk, clearing
+    //! the existing ChainstateManager, and unloading the block index.
+    //!
+    //! @returns a reference to the "restarted" ChainstateManager
+    ChainstateManager &SimulateNodeRestart() {
+        ChainstateManager &chainman = *Assert(m_node.chainman);
+
+        BOOST_TEST_MESSAGE("Simulating node restart");
+        {
+            LOCK(::cs_main);
+            for (Chainstate *cs : chainman.GetAll()) {
+                cs->ForceFlushStateToDisk();
+            }
+            chainman.ResetChainstates();
+            BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0);
+            // For robustness, ensure the old manager is destroyed before
+            // creating a new one.
+            m_node.chainman.reset();
+            m_node.chainman.reset(new ChainstateManager(::GetConfig()));
+        }
+        return *Assert(m_node.chainman);
+    }
 };
 
 //! Test basic snapshot activation.
@@ -443,4 +490,61 @@
     BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes);
 }
 
+//! Ensure that snapshot chainstates initialize properly when found on disk.
+BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup) {
+    this->SetupSnapshot();
+
+    ChainstateManager &chainman = *Assert(m_node.chainman);
+
+    fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir();
+    BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
+    BOOST_CHECK_EQUAL(snapshot_chainstate_dir,
+                      gArgs.GetDataDirNet() / "chainstate_snapshot");
+
+    BOOST_CHECK(chainman.IsSnapshotActive());
+    const BlockHash snapshot_tip_hash = WITH_LOCK(
+        chainman.GetMutex(), return chainman.ActiveTip()->GetBlockHash());
+
+    auto all_chainstates = chainman.GetAll();
+    BOOST_CHECK_EQUAL(all_chainstates.size(), 2);
+
+    // Test that simulating a shutdown (resetting ChainstateManager) and then
+    // performing chainstate reinitializing successfully cleans up the
+    // background-validation chainstate data, and we end up with a single
+    // chainstate that is at tip.
+    ChainstateManager &chainman_restarted = this->SimulateNodeRestart();
+
+    BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
+
+    // This call reinitializes the chainstates.
+    this->LoadVerifyActivateChainstate(::GetConfig());
+
+    {
+        LOCK(chainman_restarted.GetMutex());
+        BOOST_CHECK_EQUAL(chainman_restarted.GetAll().size(), 2);
+        BOOST_CHECK(chainman_restarted.IsSnapshotActive());
+        BOOST_CHECK(!chainman_restarted.IsSnapshotValidated());
+
+        BOOST_CHECK_EQUAL(chainman_restarted.ActiveTip()->GetBlockHash(),
+                          snapshot_tip_hash);
+        BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
+    }
+
+    BOOST_TEST_MESSAGE("Ensure we can mine blocks on top of the initialized "
+                       "snapshot chainstate");
+    mineBlocks(10);
+    {
+        LOCK(chainman_restarted.GetMutex());
+        BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
+
+        // Background chainstate should be unaware of new blocks on the snapshot
+        // chainstate.
+        for (const Chainstate *cs : chainman_restarted.GetAll()) {
+            if (cs != &chainman_restarted.ActiveChainstate()) {
+                BOOST_CHECK_EQUAL(cs->m_chain.Height(), 110);
+            }
+        }
+    }
+}
+
 BOOST_AUTO_TEST_SUITE_END()