diff --git a/src/box/box.cc b/src/box/box.cc
index 543c1c01aa924990b3de0d0d460aa47f59b53af8..3f7494a0241800fa458cb28cdd9a889b4d26724e 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -121,6 +121,8 @@ const char *box_ballot_event_key = "internal.ballot";
  */
 static 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.
@@ -2670,6 +2672,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)
 {
@@ -4084,7 +4092,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"),
@@ -4109,7 +4117,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();
@@ -4409,12 +4417,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.
@@ -4501,7 +4505,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();
 	}
@@ -4528,7 +4532,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();
 		}
@@ -4568,7 +4572,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);
@@ -4643,6 +4647,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 27c5430d249a0711ee8d79b5f94aa3566cff41ba..720cd323158c0f23bee54951ac81605bf611e617 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -90,6 +90,9 @@ extern double txn_timeout_default;
 /** "internal.ballot" built-in event key. */
 extern const char *box_ballot_event_key;
 
+/** box.cfg.force_recovery. */
+extern bool box_is_force_recovery;
+
 /*
  * Initialize box library
  * @throws C++ exception
@@ -291,6 +294,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 db5c5fed0ea92030a3c01cfc26c27c0bbc188e8c..ff6deb765cdfd083f1fe1657de1d6e8de96fccdd 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -470,7 +470,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,