diff --git a/src/box/box.cc b/src/box/box.cc
index 5d9d1a1f0867a7b7068edb5d48dff22650afd6df..4ea445c3710b21774be10769f39c48adb4f8b10b 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -116,6 +116,8 @@ const char *box_ballot_event_key = "internal.ballot";
 
 struct tt_uuid bootstrap_leader_uuid;
 
+bool box_is_force_recovery = false;
+
 /**
  * Set if backup is in progress, i.e. box_backup_start() was
  * called but box_backup_stop() hasn't been yet.
@@ -2798,6 +2800,12 @@ box_set_vinyl_timeout(void)
 	vinyl_engine_set_timeout(vinyl,	cfg_getd("vinyl_timeout"));
 }
 
+void
+box_set_force_recovery(void)
+{
+	box_is_force_recovery = cfg_geti("force_recovery");
+}
+
 void
 box_set_net_msg_max(void)
 {
@@ -4238,7 +4246,7 @@ engine_init()
 	 */
 	struct memtx_engine *memtx;
 	memtx = memtx_engine_new_xc(cfg_gets("memtx_dir"),
-				    cfg_geti("force_recovery"),
+				    box_is_force_recovery,
 				    cfg_getd("memtx_memory"),
 				    cfg_geti("memtx_min_tuple_size"),
 				    cfg_geti("strip_core"),
@@ -4263,7 +4271,7 @@ engine_init()
 				    cfg_geti64("vinyl_memory"),
 				    cfg_geti("vinyl_read_threads"),
 				    cfg_geti("vinyl_write_threads"),
-				    cfg_geti("force_recovery"));
+				    box_is_force_recovery);
 	engine_register((struct engine *)vinyl);
 	box_set_vinyl_max_tuple_size();
 	box_set_vinyl_cache();
@@ -4565,12 +4573,8 @@ local_recovery(const struct tt_uuid *instance_uuid,
 	auto stream_guard = make_scoped_guard([&]{
 		wal_stream_abort(&wal_stream);
 	});
-
-	struct recovery *recovery;
-	bool is_force_recovery = cfg_geti("force_recovery");
-	recovery = recovery_new(wal_dir(), is_force_recovery,
-				checkpoint_vclock);
-
+	struct recovery *recovery = recovery_new(
+		wal_dir(), box_is_force_recovery, checkpoint_vclock);
 	/*
 	 * Make sure we report the actual recovery position
 	 * in box.info while local recovery is in progress.
@@ -4657,7 +4661,7 @@ local_recovery(const struct tt_uuid *instance_uuid,
 		diag_set(XlogError, "found a not finished transaction "
 			 "in the log");
 		wal_stream_abort(&wal_stream);
-		if (!is_force_recovery)
+		if (!box_is_force_recovery)
 			diag_raise();
 		diag_log();
 	}
@@ -4684,7 +4688,7 @@ local_recovery(const struct tt_uuid *instance_uuid,
 			diag_set(XlogError, "found a not finished transaction "
 				 "in the log in hot standby mode");
 			wal_stream_abort(&wal_stream);
-			if (!is_force_recovery)
+			if (!box_is_force_recovery)
 				diag_raise();
 			diag_log();
 		}
@@ -4724,7 +4728,7 @@ local_recovery(const struct tt_uuid *instance_uuid,
 				   "recovered data %s",
 				   vclock_to_string(&replicaset.vclock),
 				   vclock_to_string(&recovery->vclock));
-		if (is_force_recovery) {
+		if (box_is_force_recovery) {
 			say_warn("%s: ignoring, because 'force_recovery' "
 				 "configuration option is set.", mismatch_str);
 			vclock_copy(&replicaset.vclock, &recovery->vclock);
@@ -4799,6 +4803,7 @@ box_is_configured(void)
 static void
 box_cfg_xc(void)
 {
+	box_set_force_recovery();
 	box_storage_init();
 	title("loading");
 
diff --git a/src/box/box.h b/src/box/box.h
index 1f8f44c648b2143b84743dcea17a33e3f1609d62..e582f9c9bca334cf96e153eeba991b2a75338446 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -98,6 +98,9 @@ extern const char *box_ballot_event_key;
  */
 extern struct tt_uuid bootstrap_leader_uuid;
 
+/** box.cfg.force_recovery. */
+extern bool box_is_force_recovery;
+
 /*
  * Initialize box library
  * @throws C++ exception
@@ -299,6 +302,7 @@ void box_set_vinyl_memory(void);
 void box_set_vinyl_max_tuple_size(void);
 void box_set_vinyl_cache(void);
 void box_set_vinyl_timeout(void);
+void box_set_force_recovery(void);
 int box_set_election_mode(void);
 int box_set_election_timeout(void);
 int box_set_election_fencing_mode(void);
diff --git a/src/box/lua/cfg.cc b/src/box/lua/cfg.cc
index 38ed523915ef38561e23b305ea3aa5ad995dde3b..5812374529dd72be0496c8885a07e83ad487dfd1 100644
--- a/src/box/lua/cfg.cc
+++ b/src/box/lua/cfg.cc
@@ -262,6 +262,14 @@ lbox_cfg_set_vinyl_timeout(struct lua_State *L)
 	return 0;
 }
 
+static int
+lbox_cfg_set_force_recovery(struct lua_State *L)
+{
+	(void)L;
+	box_set_force_recovery();
+	return 0;
+}
+
 static int
 lbox_cfg_set_net_msg_max(struct lua_State *L)
 {
@@ -462,6 +470,7 @@ box_lua_cfg_init(struct lua_State *L)
 		{"cfg_set_vinyl_max_tuple_size", lbox_cfg_set_vinyl_max_tuple_size},
 		{"cfg_set_vinyl_cache", lbox_cfg_set_vinyl_cache},
 		{"cfg_set_vinyl_timeout", lbox_cfg_set_vinyl_timeout},
+		{"cfg_set_force_recovery", lbox_cfg_set_force_recovery},
 		{"cfg_set_election_mode", lbox_cfg_set_election_mode},
 		{"cfg_set_election_timeout", lbox_cfg_set_election_timeout},
 		{"cfg_set_election_fencing_mode", lbox_cfg_set_election_fencing_mode},
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index d4f3fae9e0dad4381e0b387a55995cafa9eb84ac..4a0c0f6e83b935f9173e419f91a6129f9aef215f 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -468,7 +468,7 @@ local dynamic_cfg = {
     custom_proc_title       = function()
         require('title').update(box.cfg.custom_proc_title)
     end,
-    force_recovery          = nop,
+    force_recovery          = private.cfg_set_force_recovery,
     election_mode           = private.cfg_set_election_mode,
     election_timeout        = private.cfg_set_election_timeout,
     election_fencing_mode = private.cfg_set_election_fencing_mode,