diff --git a/src/box/wal.cc b/src/box/wal.cc
index 000cd520aa0f5d3d717799f15c51ecc04e7014fd..960c9d048ef816229045439bb5208d499651ec49 100644
--- a/src/box/wal.cc
+++ b/src/box/wal.cc
@@ -570,14 +570,14 @@ wal_assign_lsn(struct wal_writer *writer, struct xrow_header **row,
 	       struct xrow_header **end)
 {
 	/** Assign LSN to all local rows. */
-	if ((*row)->replica_id == 0) {
-		for ( ; row < end; row++) {
+	for ( ; row < end; row++) {
+		if ((*row)->replica_id == 0) {
 			(*row)->lsn = vclock_inc(&writer->vclock, instance_id);
 			(*row)->replica_id = instance_id;
+		} else {
+			vclock_follow(&writer->vclock, (*row)->replica_id,
+				      (*row)->lsn);
 		}
-	} else {
-		struct xrow_header *last = end[-1];
-		vclock_follow(&writer->vclock, last->replica_id, last->lsn);
 	}
 }
 
diff --git a/test/replication/on_replace.lua b/test/replication/on_replace.lua
new file mode 100644
index 0000000000000000000000000000000000000000..7e49efe1f7427c2f1dd7d8995a96828e21b9072a
--- /dev/null
+++ b/test/replication/on_replace.lua
@@ -0,0 +1,34 @@
+#!/usr/bin/env tarantool
+
+-- get instance name from filename (on_replace1.lua => on_replace1)
+local INSTANCE_ID = string.match(arg[0], "%d")
+local USER = 'cluster'
+local PASSWORD = 'somepassword'
+local SOCKET_DIR = require('fio').cwd()
+local function instance_uri(instance_id)
+    --return 'localhost:'..(3310 + instance_id)
+    return SOCKET_DIR..'/on_replace'..instance_id..'.sock';
+end
+
+-- start console first
+require('console').listen(os.getenv('ADMIN'))
+
+box.cfg({
+    listen = instance_uri(INSTANCE_ID);
+--    log_level = 7;
+    replication = {
+        USER..':'..PASSWORD..'@'..instance_uri(1);
+        USER..':'..PASSWORD..'@'..instance_uri(2);
+    };
+})
+
+env = require('test_run')
+test_run = env.new()
+engine = test_run:get_cfg('engine')
+
+box.once("bootstrap", function()
+    box.schema.user.create(USER, { password = PASSWORD })
+    box.schema.user.grant(USER, 'replication')
+    box.schema.space.create('test', {engine = engine})
+    box.space.test:create_index('primary')
+end)
diff --git a/test/replication/on_replace.result b/test/replication/on_replace.result
index 15338ff051df4803dbbc4b5d55074f93f360c835..1736c53b746dcaeaefb2654bcce86c71e00a7690 100644
--- a/test/replication/on_replace.result
+++ b/test/replication/on_replace.result
@@ -94,3 +94,86 @@ box.space.test:drop()
 box.schema.user.revoke('guest', 'replication')
 ---
 ...
+-- gh-2682 on_replace on slave server with data change
+SERVERS = { 'on_replace1', 'on_replace2' }
+---
+...
+test_run:create_cluster(SERVERS)
+---
+...
+test_run:wait_fullmesh(SERVERS)
+---
+...
+test_run:cmd('switch on_replace1')
+---
+- true
+...
+fiber = require'fiber'
+---
+...
+s1 = box.schema.space.create('s1')
+---
+...
+_ = s1:create_index('pk')
+---
+...
+s2 = box.schema.space.create('s2')
+---
+...
+_ = s2:create_index('pk')
+---
+...
+test_run:cmd('switch on_replace2')
+---
+- true
+...
+fiber = require'fiber'
+---
+...
+while box.space.s2 == nil do fiber.sleep(0.00001) end
+---
+...
+_ = box.space.s1:on_replace(function (old, new) box.space.s2:replace(new) end)
+---
+...
+test_run:cmd('switch on_replace1')
+---
+- true
+...
+box.space.s1:replace({1, 2, 3, 4})
+---
+- [1, 2, 3, 4]
+...
+while #(box.space.s2:select()) == 0 do fiber.sleep(0.00001) end
+---
+...
+test_run:cmd('switch on_replace2')
+---
+- true
+...
+box.space.s1:select()
+---
+- - [1, 2, 3, 4]
+...
+box.space.s2:select()
+---
+- - [1, 2, 3, 4]
+...
+test_run:cmd('switch on_replace1')
+---
+- true
+...
+box.space.s1:select()
+---
+- - [1, 2, 3, 4]
+...
+box.space.s2:select()
+---
+- - [1, 2, 3, 4]
+...
+_ = test_run:cmd('switch default')
+---
+...
+test_run:drop_cluster(SERVERS)
+---
+...
diff --git a/test/replication/on_replace.test.lua b/test/replication/on_replace.test.lua
index 12869031e72a7b60cd28f92e6d8478613227e52f..10bba2ddf06187d8389a3d8fa3c1dfb583bd19f3 100644
--- a/test/replication/on_replace.test.lua
+++ b/test/replication/on_replace.test.lua
@@ -39,3 +39,37 @@ test_run:cmd("stop server replica")
 test_run:cmd("cleanup server replica")
 box.space.test:drop()
 box.schema.user.revoke('guest', 'replication')
+
+
+-- gh-2682 on_replace on slave server with data change
+
+SERVERS = { 'on_replace1', 'on_replace2' }
+test_run:create_cluster(SERVERS)
+test_run:wait_fullmesh(SERVERS)
+
+test_run:cmd('switch on_replace1')
+fiber = require'fiber'
+s1 = box.schema.space.create('s1')
+_ = s1:create_index('pk')
+s2 = box.schema.space.create('s2')
+_ = s2:create_index('pk')
+
+test_run:cmd('switch on_replace2')
+fiber = require'fiber'
+while box.space.s2 == nil do fiber.sleep(0.00001) end
+_ = box.space.s1:on_replace(function (old, new) box.space.s2:replace(new) end)
+
+test_run:cmd('switch on_replace1')
+box.space.s1:replace({1, 2, 3, 4})
+while #(box.space.s2:select()) == 0 do fiber.sleep(0.00001) end
+
+test_run:cmd('switch on_replace2')
+box.space.s1:select()
+box.space.s2:select()
+
+test_run:cmd('switch on_replace1')
+box.space.s1:select()
+box.space.s2:select()
+
+_ = test_run:cmd('switch default')
+test_run:drop_cluster(SERVERS)
diff --git a/test/replication/on_replace1.lua b/test/replication/on_replace1.lua
new file mode 120000
index 0000000000000000000000000000000000000000..4fb461aac2a1d6e18bd3a770f8990274e98c4d78
--- /dev/null
+++ b/test/replication/on_replace1.lua
@@ -0,0 +1 @@
+on_replace.lua
\ No newline at end of file
diff --git a/test/replication/on_replace2.lua b/test/replication/on_replace2.lua
new file mode 120000
index 0000000000000000000000000000000000000000..4fb461aac2a1d6e18bd3a770f8990274e98c4d78
--- /dev/null
+++ b/test/replication/on_replace2.lua
@@ -0,0 +1 @@
+on_replace.lua
\ No newline at end of file