diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c
index e7a9dfb3093ca32d9c2a6938328971b487b6c51d..17ae21102bfeed3ebd07f166c355831bd0e86936 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -1268,7 +1268,16 @@ memtx_space_build_index(struct space *src_space, struct index *new_index,
 
 		trigger_create(&on_replace, memtx_build_on_replace, &state,
 			       NULL);
-		trigger_add(&src_space->on_replace, &on_replace);
+		/*
+		 * If MVCC is enabled, all concurrent writes that we haven't
+		 * read will be conflicted, so we don't need to set the trigger.
+		 * Moreover, concurrent transaction can be rolled back much
+		 * later than the index will be built so the memtx_ddl_state
+		 * will be invalid in this case since it's allocated on stack
+		 * of this function.
+		 */
+		if (!memtx_tx_manager_use_mvcc_engine)
+			trigger_add(&src_space->on_replace, &on_replace);
 	}
 
 	/*
diff --git a/test/box-luatest/mvcc_ddl_test.lua b/test/box-luatest/mvcc_ddl_test.lua
index 2e2cd9c379acf51df1e7ef900b03d3689800a067..24fd45c7fc41078e6c822ff77e89f2a57151dbfa 100644
--- a/test/box-luatest/mvcc_ddl_test.lua
+++ b/test/box-luatest/mvcc_ddl_test.lua
@@ -43,3 +43,46 @@ g.test_drop_space_many_delete_statements = function(cg)
         box.internal.memtx_tx_gc(1000)
     end)
 end
+
+-- The test checks if background build of index does not crash when
+-- MVCC is enabled
+-- gh-10147
+g.test_background_build = function(cg)
+    cg.server:exec(function()
+        local txn_proxy = require("test.box.lua.txn_proxy")
+        local fiber = require('fiber')
+
+        -- Create space with tuples
+        local s = box.schema.space.create('test')
+        s:create_index('pk')
+        for i = 1, 2000 do
+            s:replace{i}
+        end
+
+        local index_built = false
+        local f = fiber.create(function()
+            s:create_index('sk')
+            index_built = true
+        end)
+        f:set_joinable(true)
+
+        -- Delete the tuples concurrently
+        local tx1 = txn_proxy:new()
+        tx1:begin()
+        for i = 1, 2000 do
+            local stmt = "box.space.test:delete{" .. i .. "}"
+            tx1(stmt)
+        end
+
+        assert(not index_built)
+        local ok = f:join()
+        t.assert(ok)
+        local res = tx1:commit()
+        -- Must be aborted by DDL
+        t.assert_equals(res,
+            {{error = "Transaction has been aborted by conflict"}})
+
+        -- Collect garbage
+        box.internal.memtx_tx_gc(1000)
+    end)
+end