diff --git a/src/box/box.cc b/src/box/box.cc
index ba77d7f5014fb29363a60d9cefd3b1094903b428..4f11901d70be7851ad9633c8de0296e1d7a5381b 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -111,13 +111,14 @@ box_check_uri(const char *source, const char *option_name)
 	}
 }
 
-static void
+static enum wal_mode
 box_check_wal_mode(const char *mode_name)
 {
 	assert(mode_name != NULL); /* checked in Lua */
 	int mode = strindex(wal_mode_STRS, mode_name, WAL_MODE_MAX);
 	if (mode == WAL_MODE_MAX)
 		tnt_raise(ClientError, ER_CFG, "wal_mode", mode_name);
+	return (enum wal_mode) mode;
 }
 
 static void
@@ -130,6 +131,17 @@ box_check_readahead(int readahead)
 	}
 }
 
+static int
+box_check_rows_per_wal(int rows_per_wal)
+{
+	/* check rows_per_wal configuration */
+	if (rows_per_wal <= 1) {
+		tnt_raise(ClientError, ER_CFG, "rows_per_wal",
+			  "the value must be greater than one");
+	}
+	return rows_per_wal;
+}
+
 void
 box_check_config()
 {
@@ -137,12 +149,9 @@ box_check_config()
 	box_check_uri(cfg_gets("listen"), "listen");
 	box_check_uri(cfg_gets("replication_source"), "replication_source");
 	box_check_readahead(cfg_geti("readahead"));
+	box_check_rows_per_wal(cfg_geti("rows_per_wal"));
+	box_check_wal_mode(cfg_gets("wal_mode"));
 
-	/* check rows_per_wal configuration */
-	if (cfg_geti("rows_per_wal") <= 1) {
-		tnt_raise(ClientError, ER_CFG, "rows_per_wal",
-			  "the value must be greater than one");
-	}
 }
 
 extern "C" void
@@ -184,16 +193,12 @@ box_set_listen(const char *uri)
 
 	if (uri != NULL)
 		coio_service_start(&binary, uri);
-
-	box_leave_local_standby_mode(NULL);
 }
 
 extern "C" void
 box_set_wal_mode(const char *mode_name)
 {
-	box_check_wal_mode(mode_name);
-	enum wal_mode mode = (enum wal_mode)
-		strindex(wal_mode_STRS, mode_name, WAL_MODE_MAX);
+	enum wal_mode mode = box_check_wal_mode(mode_name);
 	if (mode != recovery->wal_mode &&
 	    (mode == WAL_FSYNC || recovery->wal_mode == WAL_FSYNC)) {
 		tnt_raise(ClientError, ER_CFG, "wal_mode",
@@ -240,39 +245,6 @@ box_set_readahead(int readahead)
 
 /* }}} configuration bindings */
 
-void
-box_leave_local_standby_mode(void *data __attribute__((unused)))
-{
-	/*
-	 * recovery->finalize is true when listen is changed
-	 * dynamically.
-	 */
-	if (recovery->finalize)
-		return;
-
-	try {
-		recovery_finalize(recovery, cfg_geti("rows_per_wal"));
-	} catch (Exception *e) {
-		e->log();
-		panic("unable to successfully finalize recovery");
-	}
-
-	/*
-	 * notify engines about end of recovery.
-	*/
-	engine_end_recovery();
-
-	stat_cleanup(stat_base, IPROTO_TYPE_STAT_MAX);
-	box_set_wal_mode(cfg_gets("wal_mode"));
-
-	if (recovery_has_remote(recovery))
-		recovery_follow_remote(recovery);
-	/* Enter read-write mode. */
-	if (recovery->server_id > 0)
-		box_set_ro(false);
-	title("running", NULL);
-	say_info("ready to accept requests");
-}
 
 /**
  * Execute a request against a given space id with
@@ -429,89 +401,98 @@ engine_init()
 	engine_register(sophia);
 }
 
-void
-box_init()
+static inline void
+box_do_init(void)
 {
-	box_check_config();
-
-	stat_init();
-	stat_base = stat_register(iproto_type_strs, IPROTO_TYPE_STAT_MAX);
-
 	tuple_init(cfg_getd("slab_alloc_arena"),
 		   cfg_geti("slab_alloc_minimal"),
 		   cfg_geti("slab_alloc_maximal"),
 		   cfg_getd("slab_alloc_factor"));
 
-	try {
-		engine_init();
-
-		schema_init();
-		user_cache_init();
-		/*
-		 * The order is important: to initialize sessions,
-		 * we need to access the admin user, which is used
-		 * as a default session user when running triggers.
-		 */
-		session_init();
-
-		title("loading", NULL);
-
-		/* recovery initialization */
-		recovery = recovery_new(cfg_gets("snap_dir"),
-					cfg_gets("wal_dir"),
-					recover_row, NULL);
-		recovery_set_remote(recovery,
-				    cfg_gets("replication_source"));
-		recovery_setup_panic(recovery,
-				     cfg_geti("panic_on_snap_error"),
-				     cfg_geti("panic_on_wal_error"));
-
-		if (recovery_has_data(recovery)) {
-			/* Tell Sophia engine LSN it must recover to. */
-			int64_t checkpoint_id =
-				recovery_last_checkpoint(recovery);
-			engine_begin_recover_snapshot(checkpoint_id);
-			/* Process existing snapshot */
-			recover_snap(recovery);
-			engine_end_recover_snapshot();
-		} else if (recovery_has_remote(recovery)) {
-			/* Initialize a new replica */
-			replica_bootstrap(recovery);
-			engine_end_recover_snapshot();
-			box_snapshot();
-		} else {
-			/* Initialize the first server of a new cluster */
-			recovery_bootstrap(recovery);
-			box_set_cluster_uuid();
-			box_set_server_uuid();
-			engine_end_recover_snapshot();
-			box_snapshot();
-		}
-		fiber_gc();
-	} catch (Exception *e) {
-		e->log();
-		panic("can't initialize storage: %s", e->errmsg());
+	stat_init();
+	stat_base = stat_register(iproto_type_strs, IPROTO_TYPE_STAT_MAX);
+
+	engine_init();
+
+	schema_init();
+	user_cache_init();
+	/*
+	 * The order is important: to initialize sessions,
+	 * we need to access the admin user, which is used
+	 * as a default session user when running triggers.
+	 */
+	session_init();
+
+	title("loading", NULL);
+
+	/* recovery initialization */
+	recovery = recovery_new(cfg_gets("snap_dir"),
+				cfg_gets("wal_dir"),
+				recover_row, NULL);
+	recovery_set_remote(recovery,
+			    cfg_gets("replication_source"));
+	recovery_setup_panic(recovery,
+			     cfg_geti("panic_on_snap_error"),
+			     cfg_geti("panic_on_wal_error"));
+
+	if (recovery_has_data(recovery)) {
+		/* Tell Sophia engine LSN it must recover to. */
+		int64_t checkpoint_id =
+			recovery_last_checkpoint(recovery);
+		engine_begin_recover_snapshot(checkpoint_id);
+		/* Process existing snapshot */
+		recover_snap(recovery);
+		engine_end_recover_snapshot();
+	} else if (recovery_has_remote(recovery)) {
+		/* Initialize a new replica */
+		replica_bootstrap(recovery);
+		engine_end_recover_snapshot();
+		box_snapshot();
+	} else {
+		/* Initialize the first server of a new cluster */
+		recovery_bootstrap(recovery);
+		box_set_cluster_uuid();
+		box_set_server_uuid();
+		engine_end_recover_snapshot();
+		box_snapshot();
 	}
+	fiber_gc();
 
 	title("orphan", NULL);
-	recovery_follow_local(recovery,
-			      cfg_getd("wal_dir_rescan_delay"));
+	recovery_follow_local(recovery, cfg_getd("wal_dir_rescan_delay"));
 	title("hot_standby", NULL);
 
 	iproto_init(&binary);
-	/**
-	 * listen is a dynamic option, so box_set_listen()
-	 * will be called after box_init() as long as there
-	 * is a value for listen in the configuration table.
-	 *
-	 * However, if cfg.listen is nil, box_set_listen() will
-	 * not be called - which means that we need to leave
-	 * local hot standby here. The idea is to leave
-	 * local hot standby immediately if listen is not given,
-	 * and only after binding to the listen uri otherwise.
-	 */
-	if (cfg_gets("listen") == NULL)
-		box_leave_local_standby_mode(NULL);
+	box_set_listen(cfg_gets("listen"));
+
+	int rows_per_wal = box_check_rows_per_wal(cfg_geti("rows_per_wal"));
+	enum wal_mode wal_mode = box_check_wal_mode(cfg_gets("wal_mode"));
+	recovery_finalize(recovery, wal_mode, rows_per_wal);
+
+	engine_end_recovery();
+
+	stat_cleanup(stat_base, IPROTO_TYPE_STAT_MAX);
+
+	if (recovery_has_remote(recovery))
+		recovery_follow_remote(recovery);
+	/* Enter read-write mode. */
+	if (recovery->server_id > 0)
+		box_set_ro(false);
+	title("running", NULL);
+	say_info("ready to accept requests");
+
+	fiber_gc();
+}
+
+void
+box_init()
+{
+	try {
+		box_do_init();
+	} catch (Exception *e) {
+		e->log();
+		panic("can't initialize storage: %s", e->errmsg());
+	}
 }
 
 void
diff --git a/src/box/recovery.cc b/src/box/recovery.cc
index fae8e77d49f8c82dc1f7695929dd8ffda98e2d64..3d43056d23b3317af42111560f3015a075be06e8 100644
--- a/src/box/recovery.cc
+++ b/src/box/recovery.cc
@@ -180,9 +180,6 @@ recovery_new(const char *snap_dirname, const char *wal_dirname,
 
 	xdir_create(&r->wal_dir, wal_dirname, XLOG, &r->server_uuid);
 
-	if (r->wal_mode == WAL_FSYNC)
-		(void) strcat(r->wal_dir.open_wflags, "s");
-
 	vclock_create(&r->vclock);
 
 	xdir_scan(&r->snap_dir);
@@ -522,7 +519,8 @@ recover_remaining_wals(struct recovery_state *r)
 }
 
 void
-recovery_finalize(struct recovery_state *r, int rows_per_wal)
+recovery_finalize(struct recovery_state *r, enum wal_mode wal_mode,
+		  int rows_per_wal)
 {
 
 	recovery_stop_local(r);
@@ -559,6 +557,10 @@ recovery_finalize(struct recovery_state *r, int rows_per_wal)
 		recovery_close_log(r);
 	}
 
+	r->wal_mode = wal_mode;
+	if (r->wal_mode == WAL_FSYNC)
+		(void) strcat(r->wal_dir.open_wflags, "s");
+
 	wal_writer_start(r, rows_per_wal);
 }
 
diff --git a/src/box/recovery.h b/src/box/recovery.h
index 571e67ff0d4a9182663b0bc38c5990b5e1f92773..58289bac9e5293b1741aee412ccb998c70f53717 100644
--- a/src/box/recovery.h
+++ b/src/box/recovery.h
@@ -137,7 +137,8 @@ void recover_snap(struct recovery_state *r);
 void recovery_follow_local(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay);
 void recovery_stop_local(struct recovery_state *r);
 
-void recovery_finalize(struct recovery_state *r, int rows_per_wal);
+void recovery_finalize(struct recovery_state *r, enum wal_mode mode,
+		       int rows_per_wal);
 
 int64_t wal_write(struct recovery_state *r, struct xrow_header *packet);
 
diff --git a/test/app/cfg.result b/test/app/cfg.result
index 86808fe7f6ca7e8bb2f1cbf87844ef1316cc2802..b14c3974d48aa3417d1f5f4f74311664fbafa519 100644
--- a/test/app/cfg.result
+++ b/test/app/cfg.result
@@ -1,5 +1,5 @@
 TAP version 13
-1..21
+1..25
 ok - box is not started
 ok - invalid replication_source
 ok - invalid wal_mode
@@ -9,12 +9,16 @@ ok - box is not started
 ok - exception on unconfigured box
 ok - sophia_dir is not auto-created
 ok - configured box
-ok - cfg.wal_mode default value
-ok - cfg.wal_mode default value
-ok - cfg.wal_mode change
-ok - cfg.wal_mode default value
-ok - cfg.wal_mode change
-ok - cfg.wal_mode default value
+ok - wal_mode default value
+ok - wal_mode default value
+ok - wal_mode change
+ok - wal_mode default value
+ok - wal_mode change
+ok - wal_mode default value
+ok - wal_mode fsync
+ok - wal_mode fsync -> fsync
+ok - wal_mode fsync -> write is not supported
+ok - wal_mode write -> fsync is not supported
 ok - work_dir is invalid
 ok - sophia_dir is invalid
 ok - snap_dir is invalid
diff --git a/test/app/cfg.test.lua b/test/app/cfg.test.lua
index 1b6d2c79698422b2f3602d99f3ebadf7c4572864..9bc072944dc6bcf58296556dead10d2bae62e1b2 100755
--- a/test/app/cfg.test.lua
+++ b/test/app/cfg.test.lua
@@ -3,7 +3,8 @@
 local tap = require('tap')
 local test = tap.test('cfg')
 local socket = require('socket')
-test:plan(21)
+local fio = require('fio')
+test:plan(25)
 
 --------------------------------------------------------------------------------
 -- Invalid values
@@ -54,39 +55,61 @@ test:ok(status and result == 'table', 'configured box')
 -- gh-534: Segmentation fault after two bad wal_mode settings
 --------------------------------------------------------------------------------
 
-test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value")
+test:is(box.cfg.wal_mode, "write", "wal_mode default value")
 box.cfg{wal_mode = ""}
-test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value")
+test:is(box.cfg.wal_mode, "write", "wal_mode default value")
 box.cfg{wal_mode = "none"}
-test:is(box.cfg.wal_mode, "none", "cfg.wal_mode change")
+test:is(box.cfg.wal_mode, "none", "wal_mode change")
 -- "" or NULL resets option to default value
 box.cfg{wal_mode = ""}
-test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value")
+test:is(box.cfg.wal_mode, "write", "wal_mode default value")
 box.cfg{wal_mode = "none"}
-test:is(box.cfg.wal_mode, "none", "cfg.wal_mode change")
+test:is(box.cfg.wal_mode, "none", "wal_mode change")
 box.cfg{wal_mode = require('msgpack').NULL}
-test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value")
+test:is(box.cfg.wal_mode, "write", "wal_mode default value")
+
+local tarantool_bin = arg[-1]
+local PANIC = 256
+function run_script(code)
+    local dir = fio.tempdir()
+    local script_path = fio.pathjoin(dir, 'script.lua')
+    local script = fio.open(script_path, {'O_CREAT', 'O_WRONLY', 'O_APPEND'},
+        tonumber('0777', 8))
+    script:write(code)
+    script:write("\nos.exit(0)")
+    script:close()
+    local cmd = [[/bin/sh -c 'cd "%s" && "%s" ./script.lua 2> /dev/null']]
+    local res = os.execute(string.format(cmd, dir, tarantool_bin))
+    fio.rmdir(dir)
+    return res
+end
+
+-- gh-715: Cannot switch to/from 'fsync'
+code = [[ box.cfg{ logger="tarantool.log", wal_mode = 'fsync' }; ]]
+test:is(run_script(code), 0, 'wal_mode fsync')
+
+code = [[ box.cfg{ wal_mode = 'fsync' }; box.cfg { wal_mode = 'fsync' }; ]]
+test:is(run_script(code), 0, 'wal_mode fsync -> fsync')
+
+code = [[ box.cfg{ wal_mode = 'fsync' }; box.cfg { wal_mode = 'none'} ]]
+test:is(run_script(code), PANIC, 'wal_mode fsync -> write is not supported')
+
+code = [[ box.cfg{ wal_mode = 'write' }; box.cfg { wal_mode = 'fsync'} ]]
+test:is(run_script(code), PANIC, 'wal_mode write -> fsync is not supported')
 
 -- gh-684: Inconsistency with box.cfg and directories
-local script = io.open('script.lua', 'w')
-script:write([[ box.cfg{ logger="tarantool.log", work_dir='invalid' } ]])
-script:close()
-test:isnt(os.execute("/bin/sh -c 'tarantool ./script.lua 2> /dev/null'"), 0, 'work_dir is invalid')
-
-script = io.open('script.lua', 'w')
-script:write([[ pcall( box.cfg, { logger="tarantool.log", sophia_dir='invalid' }) ]])
-script:close()
-test:isnt(os.execute("/bin/sh -c 'tarantool ./script.lua 2> /dev/null'"), 0, 'sophia_dir is invalid')
-
-script = io.open('script.lua', 'w')
-script:write([[ box.cfg{ logger="tarantool.log", snap_dir='invalid' } ]])
-script:close()
-test:isnt(os.execute("/bin/sh -c 'tarantool ./script.lua 2> /dev/null'"), 0, 'snap_dir is invalid')
-
-script = io.open('script.lua', 'w')
-script:write([[ box.cfg{ logger="tarantool.log", wal_dir='invalid' } ]])
-script:close()
-test:isnt(os.execute("/bin/sh -c 'tarantool ./script.lua 2> /dev/null'"), 0, 'wal_dir is invalid')
+local code;
+code = [[ box.cfg{ work_dir='invalid' } ]]
+test:is(run_script(code), PANIC, 'work_dir is invalid')
+
+code = [[ box.cfg{ sophia_dir='invalid' } ]]
+test:is(run_script(code), PANIC, 'sophia_dir is invalid')
+
+code = [[ box.cfg{ snap_dir='invalid' } ]]
+test:is(run_script(code), PANIC, 'snap_dir is invalid')
+
+code = [[ box.cfg{ wal_dir='invalid' } ]]
+test:is(run_script(code), PANIC, 'wal_dir is invalid')
 
 -- box.cfg { listen = xx }
 local path = './tarantool.sock'