diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 8807f75835852242491cabea356b48d99ffbc019..ea4839dea171c3f7524b3e3ccdb908104e5c8164 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -3948,6 +3948,16 @@ vy_build_insert_tuple(struct vy_env *env, struct vy_lsm *lsm,
 			return -1;
 		}
 	}
+	/*
+	 * Despite the fact that we protected mem from being
+	 * dumped, its generation still may bump due to rotation
+	 * in vy_tx_write_prepare() (insertions during index build
+	 * are still handled by on_replace_trigger). This may happen
+	 * if dump process is triggered (vy_scheduler_trigger_dump()).
+	 * Hence, to get right mem (during mem rotation it becomes
+	 * sealed i.e. read-only) we should fetch it from lsm again.
+	 */
+	mem = lsm->mem;
 
 	/* Insert the new tuple into the in-memory index. */
 	size_t mem_used_before = lsregion_used(&env->mem_env.allocator);
diff --git a/test/vinyl/gh-4810-dump-during-index-build.result b/test/vinyl/gh-4810-dump-during-index-build.result
new file mode 100644
index 0000000000000000000000000000000000000000..f55c44a1fb1811314257d69fb711c9acbf404289
--- /dev/null
+++ b/test/vinyl/gh-4810-dump-during-index-build.result
@@ -0,0 +1,150 @@
+-- test-run result file version 2
+test_run = require('test_run').new()
+ | ---
+ | ...
+
+test_run:cmd("create server test with script='vinyl/low_quota.lua'")
+ | ---
+ | - true
+ | ...
+test_run:cmd("start server test with args='13421772'")
+ | ---
+ | - true
+ | ...
+test_run:cmd('switch test')
+ | ---
+ | - true
+ | ...
+
+fiber = require 'fiber'
+ | ---
+ | ...
+
+math.randomseed(os.time())
+ | ---
+ | ...
+
+s = box.schema.space.create('test', {engine = 'vinyl'})
+ | ---
+ | ...
+_ = s:create_index('pk', {parts = {1, 'unsigned'}})
+ | ---
+ | ...
+
+--
+-- Purpose of this test is to trigger dump during secondary index build.
+-- It is worth noting that dump must be triggered by exceeding memory
+-- quota and not by invoking box.snapshot() since checkpoint process
+-- is locked by DDL latch.
+--
+
+MAX_KEY = 1000000
+ | ---
+ | ...
+MAX_VAL = 1000000
+ | ---
+ | ...
+PADDING = string.rep('x', 100)
+ | ---
+ | ...
+
+test_run:cmd("setopt delimiter ';'")
+ | ---
+ | - true
+ | ...
+
+function gen_insert()
+    pcall(s.insert, s, {math.random(MAX_KEY), math.random(MAX_VAL),
+                        math.random(MAX_VAL), math.random(MAX_VAL), PADDING})
+end;
+ | ---
+ | ...
+
+function fill_L0_without_dump()
+    local dump_watermark = box.cfg.vinyl_memory / 2
+    while box.stat.vinyl().memory.level0 < dump_watermark do
+        gen_insert()
+    end
+end;
+ | ---
+ | ...
+
+fill_L0_without_dump();
+ | ---
+ | ...
+assert(box.stat.vinyl().scheduler.dump_count == 0);
+ | ---
+ | - true
+ | ...
+
+function insert_loop()
+    while not stop do
+        gen_insert()
+    end
+    ch:put(true)
+end;
+ | ---
+ | ...
+
+function idx_build()
+    _ = s:create_index('i1', {unique = true, parts = {2, 'unsigned', 3, 'unsigned'}})
+    ch:put(true)
+end;
+ | ---
+ | ...
+
+stop = false;
+ | ---
+ | ...
+ch = fiber.channel(2);
+ | ---
+ | ...
+
+_ = fiber.create(idx_build);
+ | ---
+ | ...
+_ = fiber.create(insert_loop);
+ | ---
+ | ...
+
+fiber.sleep(3);
+ | ---
+ | ...
+
+stop = true;
+ | ---
+ | ...
+for i = 1, ch:size() do
+    ch:get()
+end;
+ | ---
+ | ...
+
+test_run:cmd("setopt delimiter ''");
+ | ---
+ | - true
+ | ...
+assert(box.stat.vinyl().scheduler.dump_count > 0)
+ | ---
+ | - true
+ | ...
+assert(s.index.i1 ~= nil)
+ | ---
+ | - true
+ | ...
+s:drop()
+ | ---
+ | ...
+
+test_run:cmd('switch default')
+ | ---
+ | - true
+ | ...
+test_run:cmd("stop server test")
+ | ---
+ | - true
+ | ...
+test_run:cmd("cleanup server test")
+ | ---
+ | - true
+ | ...
diff --git a/test/vinyl/gh-4810-dump-during-index-build.test.lua b/test/vinyl/gh-4810-dump-during-index-build.test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..7b7026498b415976fbd11e8a65d4f9faa6d46055
--- /dev/null
+++ b/test/vinyl/gh-4810-dump-during-index-build.test.lua
@@ -0,0 +1,74 @@
+test_run = require('test_run').new()
+
+test_run:cmd("create server test with script='vinyl/low_quota.lua'")
+test_run:cmd("start server test with args='13421772'")
+test_run:cmd('switch test')
+
+fiber = require 'fiber'
+
+math.randomseed(os.time())
+
+s = box.schema.space.create('test', {engine = 'vinyl'})
+_ = s:create_index('pk', {parts = {1, 'unsigned'}})
+
+--
+-- Purpose of this test is to trigger dump during secondary index build.
+-- It is worth noting that dump must be triggered by exceeding memory
+-- quota and not by invoking box.snapshot() since checkpoint process
+-- is locked by DDL latch.
+--
+
+MAX_KEY = 1000000
+MAX_VAL = 1000000
+PADDING = string.rep('x', 100)
+
+test_run:cmd("setopt delimiter ';'")
+
+function gen_insert()
+    pcall(s.insert, s, {math.random(MAX_KEY), math.random(MAX_VAL),
+                        math.random(MAX_VAL), math.random(MAX_VAL), PADDING})
+end;
+
+function fill_L0_without_dump()
+    local dump_watermark = box.cfg.vinyl_memory / 2
+    while box.stat.vinyl().memory.level0 < dump_watermark do
+        gen_insert()
+    end
+end;
+
+fill_L0_without_dump();
+assert(box.stat.vinyl().scheduler.dump_count == 0);
+
+function insert_loop()
+    while not stop do
+        gen_insert()
+    end
+    ch:put(true)
+end;
+
+function idx_build()
+    _ = s:create_index('i1', {unique = true, parts = {2, 'unsigned', 3, 'unsigned'}})
+    ch:put(true)
+end;
+
+stop = false;
+ch = fiber.channel(2);
+
+_ = fiber.create(idx_build);
+_ = fiber.create(insert_loop);
+
+fiber.sleep(3);
+
+stop = true;
+for i = 1, ch:size() do
+    ch:get()
+end;
+
+test_run:cmd("setopt delimiter ''");
+assert(box.stat.vinyl().scheduler.dump_count > 0)
+assert(s.index.i1 ~= nil)
+s:drop()
+
+test_run:cmd('switch default')
+test_run:cmd("stop server test")
+test_run:cmd("cleanup server test")