diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java
index af614491e37b9624e60829d67e776e1f50e33e93..571df42d55706c0640c83480bbdd4a90bf85e775 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java
@@ -50,6 +50,7 @@ public interface LifecycleManager {
 	enum LifecycleState {
 
 		NOT_STARTED,
+		DB_OPEN,
 		STARTING,
 		MIGRATING_DATABASE,
 		COMPACTING_DATABASE,
@@ -83,6 +84,8 @@ public interface LifecycleManager {
 	 */
 	void registerForShutdown(ExecutorService e);
 
+	void openDatabase();
+
 	/**
 	 * Opens the {@link Database} using the given key and starts any
 	 * registered {@link Service Services}.
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt
index 2e4781ed23032f3e6a7fcc1deec6717d0f5096f7..212851be60eec309177033bec735bdcfadb95ce3 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt
@@ -25,6 +25,7 @@ import org.briarproject.mailbox.core.db.Database
 import org.briarproject.mailbox.core.db.MigrationListener
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager.LifecycleState
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE
+import org.briarproject.mailbox.core.lifecycle.LifecycleManager.LifecycleState.DB_OPEN
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager.LifecycleState.NOT_STARTED
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager.LifecycleState.RUNNING
@@ -99,30 +100,32 @@ internal class LifecycleManagerImpl @Inject constructor(
         executors.add(e)
     }
 
+    @GuardedBy("startStopWipeSemaphore")
+    override fun openDatabase() {
+        if (!startStopWipeSemaphore.tryAcquire()) {
+            LOG.info("Already starting or stopping")
+            return
+        }
+        try {
+            openDatabaseInternally()
+        } finally {
+            startStopWipeSemaphore.release()
+        }
+    }
+
     @GuardedBy("startStopWipeSemaphore")
     override fun startServices(): StartResult {
         if (!startStopWipeSemaphore.tryAcquire()) {
             LOG.info("Already starting or stopping")
             return ALREADY_RUNNING
         }
-        state.compareAndSet(NOT_STARTED, STARTING)
         return try {
-            LOG.info("Opening database")
-            var start = now()
-            val reopened = db.open(this)
-            if (reopened) logDuration(LOG, { "Reopening database" }, start)
-            else logDuration(LOG, { "Creating database" }, start)
-            // Inform hooks that DB was opened
-            db.write { txn ->
-                for (hook in openDatabaseHooks) {
-                    hook.onDatabaseOpened(txn)
-                }
-            }
+            openDatabaseInternally()
+            state.compareAndSet(DB_OPEN, STARTING)
             LOG.info("Starting services")
             state.value = STARTING_SERVICES
-            dbLatch.countDown()
             for (s in services) {
-                start = now()
+                val start = now()
                 s.startService()
                 logDuration(LOG, { "Starting service  ${s.javaClass.simpleName}" }, start)
             }
@@ -137,6 +140,26 @@ internal class LifecycleManagerImpl @Inject constructor(
         }
     }
 
+    private fun openDatabaseInternally() {
+        if (state.value != NOT_STARTED) {
+            return
+        }
+        LOG.info("Opening database")
+        var start = now()
+        val reopened = db.open(this)
+        if (reopened) logDuration(LOG, { "Reopening database" }, start)
+        else logDuration(LOG, { "Creating database" }, start)
+        // Inform hooks that DB was opened
+        db.write { txn ->
+            for (hook in openDatabaseHooks) {
+                hook.onDatabaseOpened(txn)
+            }
+        }
+        logDuration(LOG, { "Opening database" }, start)
+        state.value = DB_OPEN
+        dbLatch.countDown()
+    }
+
     // startStopWipeSemaphore is being held during this because it will be called during db.open()
     // in startServices()
     @GuardedBy("startStopWipeSemaphore")