diff --git a/src/box/vy_cache.c b/src/box/vy_cache.c
index 825bfd3b6c7f300772f6fefaec7963acd0f2c7fd..e526ab1ec1bf70f068d02469f63b90d627cf683f 100644
--- a/src/box/vy_cache.c
+++ b/src/box/vy_cache.c
@@ -766,11 +766,11 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr,
 	if (!itr->search_started || itr->version == itr->cache->version)
 		return 0;
 
+	bool pos_changed = false;
 	itr->version = itr->cache->version;
-	struct tuple *prev_stmt = itr->curr_stmt;
-	if ((prev_stmt == NULL && itr->iterator_type == ITER_EQ) ||
-	    (prev_stmt != NULL &&
-	     prev_stmt != vy_cache_iterator_curr_stmt(itr))) {
+	if ((itr->curr_stmt == NULL && itr->iterator_type == ITER_EQ) ||
+	    (itr->curr_stmt != NULL &&
+	     itr->curr_stmt != vy_cache_iterator_curr_stmt(itr))) {
 		/*
 		 * EQ search ended or the iterator was invalidated.
 		 * In either case the best we can do is restart the
@@ -778,6 +778,7 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr,
 		 */
 		*stop = vy_cache_iterator_seek(itr, last_stmt);
 		vy_cache_iterator_skip_to_read_view(itr, stop);
+		pos_changed = true;
 	} else {
 		/*
 		 * The iterator position is still valid, but new
@@ -797,7 +798,7 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr,
 		struct key_def *def = itr->cache->cmp_def;
 		struct vy_cache_tree *tree = &itr->cache->cache_tree;
 		struct vy_cache_tree_iterator pos = itr->curr_pos;
-		if (prev_stmt == NULL)
+		if (itr->curr_stmt == NULL)
 			pos = vy_cache_tree_invalid_iterator();
 		while (true) {
 			if (dir > 0)
@@ -818,11 +819,14 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr,
 				itr->curr_stmt = entry->stmt;
 				tuple_ref(itr->curr_stmt);
 				*stop = vy_cache_iterator_is_stop(itr, entry);
+				pos_changed = true;
 			}
 			if (cmp == 0)
 				break;
 		}
 	}
+	if (!pos_changed)
+		return 0;
 
 	vy_history_cleanup(history);
 	if (itr->curr_stmt != NULL) {
@@ -830,9 +834,8 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr,
 					   itr->curr_stmt);
 		if (vy_history_append_stmt(history, itr->curr_stmt) != 0)
 			return -1;
-		return prev_stmt != itr->curr_stmt;
 	}
-	return 0;
+	return 1;
 }
 
 void
diff --git a/src/box/vy_mem.c b/src/box/vy_mem.c
index 7fa90cbd541183dd8d157484566d724e9fd6a4c6..e3b40083bba809c38968868f65750854283aaba0 100644
--- a/src/box/vy_mem.c
+++ b/src/box/vy_mem.c
@@ -595,10 +595,7 @@ vy_mem_iterator_restore(struct vy_mem_iterator *itr,
 	if (!itr->search_started || itr->version == itr->mem->version)
 		return 0;
 
-	const struct tuple *prev_stmt = itr->curr_stmt;
 	vy_mem_iterator_seek(itr, last_stmt);
-	if (prev_stmt == itr->curr_stmt)
-		return 0;
 
 	vy_history_cleanup(history);
 	if (itr->curr_stmt != NULL &&
diff --git a/src/box/vy_read_iterator.c b/src/box/vy_read_iterator.c
index 2864a2802e86129582ba7f0d0c3aa72b664d7d2f..ac8a410dbab60c15fc39e02b27a76a3dc554e45b 100644
--- a/src/box/vy_read_iterator.c
+++ b/src/box/vy_read_iterator.c
@@ -424,7 +424,9 @@ vy_read_iterator_restore_mem(struct vy_read_iterator *itr,
 		 * Make sure we don't read the old value
 		 * from the cache while applying UPSERTs.
 		 */
-		itr->src[itr->cache_src].front_id = 0;
+		struct vy_read_src *cache_src = &itr->src[itr->cache_src];
+		if (cache_src->front_id == itr->front_id)
+			vy_history_cleanup(&cache_src->history);
 	}
 	src->front_id = itr->front_id;
 	return 0;
diff --git a/src/box/vy_tx.c b/src/box/vy_tx.c
index 5280befff5028353508d0266d9527eac147c8add..df3e5ec4fd0c32f362a291f1fed5c61b5d6cc797 100644
--- a/src/box/vy_tx.c
+++ b/src/box/vy_tx.c
@@ -1285,10 +1285,7 @@ vy_txw_iterator_restore(struct vy_txw_iterator *itr,
 	if (!itr->search_started || itr->version == itr->tx->write_set_version)
 		return 0;
 
-	struct txv *prev_txv = itr->curr_txv;
 	vy_txw_iterator_seek(itr, last_stmt);
-	if (prev_txv == itr->curr_txv)
-		return 0;
 
 	vy_history_cleanup(history);
 	if (itr->curr_txv != NULL) {
diff --git a/test/vinyl/stat.result b/test/vinyl/stat.result
index 08da16587d840c57a730dc93af26da9eda0b3422..ff73d42af1d8b86bd4de96f9dd7a7651d5222c55 100644
--- a/test/vinyl/stat.result
+++ b/test/vinyl/stat.result
@@ -716,8 +716,8 @@ stat_diff(istat(), st)
       rows: 5
       bytes: 5305
     get:
-      rows: 9
-      bytes: 9549
+      rows: 5
+      bytes: 5305
   txw:
     iterator:
       lookup: 1
diff --git a/test/vinyl/upsert.result b/test/vinyl/upsert.result
index 6c6d03d6d8924b5f358b2ebb7542422b5c856814..c807b5b52d839d39f77e36817b009a8035d78034 100644
--- a/test/vinyl/upsert.result
+++ b/test/vinyl/upsert.result
@@ -791,3 +791,47 @@ s:select({100}, 'GE')
 s:drop()
 ---
 ...
+--
+-- Check that read iterator ignores a cached statement in case
+-- the current key is updated while it yields on disk read.
+--
+fiber = require('fiber')
+---
+...
+s = box.schema.space.create('test', {engine = 'vinyl'})
+---
+...
+_ = s:create_index('pk')
+---
+...
+s:replace{10, 10}
+---
+- [10, 10]
+...
+box.snapshot()
+---
+- ok
+...
+s:get(10) -- add [10, 10] to the cache
+---
+- [10, 10]
+...
+ch = fiber.channel(1)
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+_ = fiber.create(function() ch:put(s:select()) end)
+s:upsert({10, 10}, {{'+', 2, 10}})
+test_run:cmd("setopt delimiter ''");
+---
+...
+ch:get() -- should see the UPSERT and return [10, 20]
+---
+- - [10, 20]
+...
+s:drop()
+---
+...
diff --git a/test/vinyl/upsert.test.lua b/test/vinyl/upsert.test.lua
index ef83e0f6f513856a4b2266740b0f725a1a582375..cf2873606098ee7fdcf92c1c0bd7c51d27030152 100644
--- a/test/vinyl/upsert.test.lua
+++ b/test/vinyl/upsert.test.lua
@@ -325,3 +325,21 @@ s:upsert({100}, {{'+', 2, 100}})
 s:select({100}, 'GE')
 
 s:drop()
+
+--
+-- Check that read iterator ignores a cached statement in case
+-- the current key is updated while it yields on disk read.
+--
+fiber = require('fiber')
+s = box.schema.space.create('test', {engine = 'vinyl'})
+_ = s:create_index('pk')
+s:replace{10, 10}
+box.snapshot()
+s:get(10) -- add [10, 10] to the cache
+ch = fiber.channel(1)
+test_run:cmd("setopt delimiter ';'")
+_ = fiber.create(function() ch:put(s:select()) end)
+s:upsert({10, 10}, {{'+', 2, 10}})
+test_run:cmd("setopt delimiter ''");
+ch:get() -- should see the UPSERT and return [10, 20]
+s:drop()