diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 17d42dfa93c20df2e39cc1b3a644c39741c258f7..b0642d374d6bd7545a2bfcad7e8cf26ea2e015dd 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -232,21 +232,25 @@ struct vinyl_iterator {
 	struct vy_env *env;
 	/** Vinyl index this iterator is for. */
 	struct vy_index *index;
+	/** Active transaction or NULL if autocommit. */
+	struct vy_tx *tx;
 	/**
-	 * Points either to tx_autocommit for autocommit mode
-	 * or to a multi-statement transaction active when the
-	 * iterator was created.
+	 * Read view to use for the iteration. Points either to
+	 * tx->read_view or to rv_autocommit if autocommit.
 	 */
-	struct vy_tx *tx;
+	const struct vy_read_view **rv;
 	/** Search key. */
 	struct tuple *key;
 	/** Vinyl read iterator. */
 	struct vy_read_iterator iterator;
 	/**
-	 * Built-in transaction created when iterator is opened
-	 * in autocommit mode.
+	 * If an iterator is open in autocommit mode, we create
+	 * a read view for it immediately so as not to waste
+	 * memory on tracking reads for conflict resolution.
+	 * The following member points to the read view used by
+	 * the iterator.
 	 */
-	struct vy_tx tx_autocommit;
+	struct vy_read_view *rv_autocommit;
 	/** Trigger invoked when tx ends to close the iterator. */
 	struct trigger on_tx_destroy;
 };
@@ -2811,6 +2815,16 @@ vinyl_engine_end_recovery(struct engine *engine)
 		vy_gc(e, e->recovery, VY_GC_INCOMPLETE, INT64_MAX);
 		vy_recovery_delete(e->recovery);
 		e->recovery = NULL;
+		/*
+		 * During WAL recovery we skip WAL rows that have
+		 * already been dumped to disk so the LSN last seen
+		 * by the transaction manager after WAL recovery is
+		 * complete may be less than the newest LSN actually
+		 * stored on disk. Update the LSN to make sure that
+		 * the iterator sees all data when open in a read
+		 * view.
+		 */
+		e->xm->lsn = vclock_sum(e->recovery_vclock);
 		e->recovery_vclock = NULL;
 		e->status = VINYL_ONLINE;
 		vy_quota_set_limit(&e->quota, e->memory);
@@ -3716,15 +3730,6 @@ vy_squash_schedule(struct vy_index *index, struct tuple *stmt, void *arg)
 
 /* {{{ Cursor */
 
-static void
-vinyl_iterator_on_tx_destroy(struct trigger *trigger, void *event)
-{
-	(void)event;
-	struct vinyl_iterator *it = container_of(trigger,
-			struct vinyl_iterator, on_tx_destroy);
-	it->tx = NULL;
-}
-
 static int
 vinyl_iterator_last(struct iterator *base, struct tuple **ret)
 {
@@ -3741,18 +3746,11 @@ vinyl_iterator_close(struct vinyl_iterator *it)
 	it->index = NULL;
 	tuple_unref(it->key);
 	it->key = NULL;
-	if (it->tx == &it->tx_autocommit) {
-		/*
-		 * Rollback the automatic transaction.
-		 * Use vy_tx_destroy() so as not to spoil
-		 * the statistics of rollbacks issued by
-		 * user transactions.
-		 */
-		vy_tx_destroy(it->tx);
-	} else {
-		trigger_clear(&it->on_tx_destroy);
-	}
 	it->tx = NULL;
+	it->rv = NULL;
+	trigger_clear(&it->on_tx_destroy);
+	if (it->rv_autocommit != NULL)
+		tx_manager_destroy_read_view(it->env->xm, it->rv_autocommit);
 	it->base.next = vinyl_iterator_last;
 }
 
@@ -3763,12 +3761,8 @@ vinyl_iterator_next(struct iterator *base, struct tuple **ret)
 	struct vinyl_iterator *it = (struct vinyl_iterator *)base;
 	struct tuple *tuple;
 
-	if (it->tx == NULL) {
-		diag_set(ClientError, ER_CURSOR_NO_TRANSACTION);
-		goto fail;
-	}
-	if (it->tx->state == VINYL_TX_ABORT || it->tx->read_view->is_aborted) {
-		diag_set(ClientError, ER_READ_VIEW_ABORTED);
+	if ((*it->rv)->is_aborted ||
+	    (it->tx != NULL && it->tx->state == VINYL_TX_ABORT)) {
 		goto fail;
 	}
 
@@ -3784,17 +3778,17 @@ vinyl_iterator_next(struct iterator *base, struct tuple **ret)
 
 	if (it->index->id > 0) {
 		/* Get the full tuple from the primary index. */
-		if (vy_index_get(it->index->pk, it->tx,
-				 vy_tx_read_view(it->tx),
+		if (vy_index_get(it->index->pk, it->tx, it->rv,
 				 tuple, &tuple) != 0)
 			goto fail;
 	} else {
 		tuple_ref(tuple);
 	}
 	*ret = tuple_bless(tuple);
-	tuple_unref(*ret);
+	tuple_unref(tuple);
 	if (*ret == NULL)
 		goto fail;
+
 	return 0;
 fail:
 	vinyl_iterator_close(it);
@@ -3806,11 +3800,30 @@ vinyl_iterator_free(struct iterator *base)
 {
 	assert(base->free == vinyl_iterator_free);
 	struct vinyl_iterator *it = (struct vinyl_iterator *)base;
-	if (base->next != vinyl_iterator_last)
+	if (it->index != NULL)
 		vinyl_iterator_close(it);
 	mempool_free(&it->env->iterator_pool, it);
 }
 
+static int
+vinyl_iterator_no_tx(struct iterator *base, struct tuple **ret)
+{
+	(void)base;
+	(void)ret;
+	diag_set(ClientError, ER_CURSOR_NO_TRANSACTION);
+	return -1;
+}
+
+static void
+vinyl_iterator_on_tx_destroy(struct trigger *trigger, void *event)
+{
+	(void)event;
+	struct vinyl_iterator *it = container_of(trigger,
+			struct vinyl_iterator, on_tx_destroy);
+	vinyl_iterator_close(it);
+	it->base.next = vinyl_iterator_no_tx;
+}
+
 static struct iterator *
 vinyl_index_create_iterator(struct index *base, enum iterator_type type,
 			    const char *key, uint32_t part_count)
@@ -3821,20 +3834,18 @@ vinyl_index_create_iterator(struct index *base, enum iterator_type type,
 	if (type > ITER_GT) {
 		diag_set(UnsupportedIndexFeature, base->def,
 			 "requested iterator type");
-		return NULL;
+		goto err;
 	}
 
 	struct vinyl_iterator *it = mempool_alloc(&env->iterator_pool);
 	if (it == NULL) {
 	        diag_set(OutOfMemory, sizeof(struct vinyl_iterator),
 			 "mempool", "struct vinyl_iterator");
-		return NULL;
+		goto err;
 	}
 	it->key = vy_stmt_new_select(index->env->key_format, key, part_count);
-	if (it->key == NULL) {
-		mempool_free(&env->iterator_pool, it);
-		return NULL;
-	}
+	if (it->key == NULL)
+		goto err_key;
 
 	iterator_create(&it->base, base);
 	it->base.next = vinyl_iterator_next;
@@ -3844,6 +3855,11 @@ vinyl_index_create_iterator(struct index *base, enum iterator_type type,
 	it->index = index;
 	vy_index_ref(index);
 
+	it->rv_autocommit = NULL;
+	trigger_create(&it->on_tx_destroy,
+		       vinyl_iterator_on_tx_destroy, NULL, NULL);
+
+	const struct vy_read_view **rv;
 	struct vy_tx *tx = in_txn() ? in_txn()->engine_tx : NULL;
 	assert(tx == NULL || tx->state == VINYL_TX_READY);
 	if (tx != NULL) {
@@ -3851,18 +3867,27 @@ vinyl_index_create_iterator(struct index *base, enum iterator_type type,
 		 * Register a trigger that will abort this iterator
 		 * when the transaction ends.
 		 */
-		trigger_create(&it->on_tx_destroy,
-			       vinyl_iterator_on_tx_destroy, NULL, NULL);
 		trigger_add(&tx->on_destroy, &it->on_tx_destroy);
+		rv = (const struct vy_read_view **)&tx->read_view;
 	} else {
-		tx = &it->tx_autocommit;
-		vy_tx_create(env->xm, tx);
+		it->rv_autocommit = tx_manager_read_view(env->xm);
+		if (it->rv_autocommit == NULL)
+			goto err_rv;
+		rv = (const struct vy_read_view **)&it->rv_autocommit;
 	}
 	it->tx = tx;
+	it->rv = rv;
 
-	vy_read_iterator_open(&it->iterator, index, tx, type, it->key,
-			      (const struct vy_read_view **)&tx->read_view);
+	vy_read_iterator_open(&it->iterator, index, tx, type, it->key, rv);
 	return (struct iterator *)it;
+
+err_rv:
+	vy_index_unref(index);
+	tuple_unref(it->key);
+err_key:
+	mempool_free(&env->iterator_pool, it);
+err:
+	return NULL;
 }
 
 static int
diff --git a/src/box/vy_tx.c b/src/box/vy_tx.c
index 2c7c66714ab55c42694b8aba0ac4524e2a53f269..8fde79f019088686a066bf198ef167e845cf281c 100644
--- a/src/box/vy_tx.c
+++ b/src/box/vy_tx.c
@@ -133,8 +133,7 @@ tx_manager_delete(struct tx_manager *xm)
 	free(xm);
 }
 
-/** Create or reuse an instance of a read view. */
-static struct vy_read_view *
+struct vy_read_view *
 tx_manager_read_view(struct tx_manager *xm)
 {
 	struct vy_read_view *rv;
@@ -177,8 +176,7 @@ tx_manager_read_view(struct tx_manager *xm)
 	return rv;
 }
 
-/** Dereference and possibly destroy a read view. */
-static void
+void
 tx_manager_destroy_read_view(struct tx_manager *xm,
 			     const struct vy_read_view *read_view)
 {
@@ -277,7 +275,8 @@ vy_tx_read_set_free_cb(vy_tx_read_set_t *read_set,
 	return NULL;
 }
 
-void
+/** Initialize a tx object. */
+static void
 vy_tx_create(struct tx_manager *xm, struct vy_tx *tx)
 {
 	stailq_create(&tx->log);
@@ -292,7 +291,8 @@ vy_tx_create(struct tx_manager *xm, struct vy_tx *tx)
 	rlist_create(&tx->on_destroy);
 }
 
-void
+/** Destroy a tx object. */
+static void
 vy_tx_destroy(struct vy_tx *tx)
 {
 	trigger_run(&tx->on_destroy, NULL);
diff --git a/src/box/vy_tx.h b/src/box/vy_tx.h
index 2ed4800fe2134d58bd8e995751424bd85370deb8..7d5ce23e83a8d0e0041b1711b90cc026db0c3b39 100644
--- a/src/box/vy_tx.h
+++ b/src/box/vy_tx.h
@@ -257,6 +257,15 @@ tx_manager_new(void);
 void
 tx_manager_delete(struct tx_manager *xm);
 
+/** Create or reuse an instance of a read view. */
+struct vy_read_view *
+tx_manager_read_view(struct tx_manager *xm);
+
+/** Dereference and possibly destroy a read view. */
+void
+tx_manager_destroy_read_view(struct tx_manager *xm,
+			     const struct vy_read_view *read_view);
+
 /*
  * Determine the lowest possible vlsn, i.e. the level below
  * which the history could be compacted.
@@ -269,14 +278,6 @@ tx_manager_delete(struct tx_manager *xm);
 int64_t
 tx_manager_vlsn(struct tx_manager *xm);
 
-/** Initialize a tx object. */
-void
-vy_tx_create(struct tx_manager *xm, struct vy_tx *tx);
-
-/** Destroy a tx object. */
-void
-vy_tx_destroy(struct vy_tx *tx);
-
 /** Begin a new transaction. */
 struct vy_tx *
 vy_tx_begin(struct tx_manager *xm);
diff --git a/test/engine/iterator.result b/test/engine/iterator.result
index 2f175580c06214771cd8348ddf33b943bed9c2f1..8a0ed69312bb788d8878e3bdf8a5d74e7f1876c8 100644
--- a/test/engine/iterator.result
+++ b/test/engine/iterator.result
@@ -4016,17 +4016,21 @@ r
   - [3, 2]
   - [3, 3]
 ...
-itr1,itr2,itr3 = s:pairs({2}, {iterator = 'REQ'})
+-- In memtx an iterator opened in autocommit mode works in
+-- the read-committed isolation level while in vinyl it
+-- creates a read view. To make sure the result is the same
+-- for both engines, start a transaction.
+inspector:cmd("setopt delimiter ';'")
 ---
+- true
 ...
+box.begin()
+itr1,itr2,itr3 = s:pairs({2}, {iterator = 'REQ'})
 s:replace{2, 4}
----
-- [2, 4]
-...
 r = {}
----
-...
 for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+box.commit()
+inspector:cmd("setopt delimiter ''");
 ---
 ...
 r
diff --git a/test/engine/iterator.test.lua b/test/engine/iterator.test.lua
index 905173ad9426fa5b7dabffe1a603c412001bafb2..69e2dee0ebdfd37a8b36240f17faf40e908515d5 100644
--- a/test/engine/iterator.test.lua
+++ b/test/engine/iterator.test.lua
@@ -337,10 +337,18 @@ r = {}
 for k,v in itr1,itr2,itr3 do table.insert(r, v) end
 r
 
+-- In memtx an iterator opened in autocommit mode works in
+-- the read-committed isolation level while in vinyl it
+-- creates a read view. To make sure the result is the same
+-- for both engines, start a transaction.
+inspector:cmd("setopt delimiter ';'")
+box.begin()
 itr1,itr2,itr3 = s:pairs({2}, {iterator = 'REQ'})
 s:replace{2, 4}
 r = {}
 for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+box.commit()
+inspector:cmd("setopt delimiter ''");
 r
 
 r = nil
diff --git a/test/vinyl/cache.result b/test/vinyl/cache.result
index a504c2e04e1eeb96ebb9ad971ee93f714ce8e0a4..576c949b06381581acc684da139d239ac9e2e50c 100644
--- a/test/vinyl/cache.result
+++ b/test/vinyl/cache.result
@@ -460,6 +460,8 @@ s:drop()
 ---
 ...
 -- Same test w/o begin/end
+--
+-- Note, select() does not update cache in autcommit mode, see gh-2534.
 s = box.schema.space.create('test', {engine = 'vinyl'})
 ---
 ...
@@ -585,9 +587,9 @@ s:select{1}
   - [1, 3, 1, '']
   - [1, 4, 1, '']
 ...
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 ---
-- false
+- true
 ...
 s:select{}
 ---
@@ -619,9 +621,9 @@ s:select{}
   - [2, 4, 2, '']
   - [3, 3, 4]
 ...
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 ---
-- false
+- true
 ...
 s:drop()
 ---
@@ -703,9 +705,9 @@ s:get{1, 2}
 ---
 - [1, 2, 1, '']
 ...
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 ---
-- false
+- true
 ...
 s:select{1}
 ---
@@ -714,9 +716,9 @@ s:select{1}
   - [1, 3, 1, '']
   - [1, 4, 1, '']
 ...
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 ---
-- false
+- true
 ...
 s:select{}
 ---
@@ -731,9 +733,9 @@ s:select{}
   - [2, 4, 2, '']
   - [3, 3, 4]
 ...
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 ---
-- false
+- true
 ...
 s:drop()
 ---
diff --git a/test/vinyl/cache.test.lua b/test/vinyl/cache.test.lua
index af6257d648abd73a5deff322fda34df92dd1d177..19693bf92d4896f932962f591be881f2b2820de5 100644
--- a/test/vinyl/cache.test.lua
+++ b/test/vinyl/cache.test.lua
@@ -166,6 +166,8 @@ pk:max()
 s:drop()
 
 -- Same test w/o begin/end
+--
+-- Note, select() does not update cache in autcommit mode, see gh-2534.
 
 s = box.schema.space.create('test', {engine = 'vinyl'})
 pk = s:create_index('pk')
@@ -216,13 +218,13 @@ s:select{1}
 stat_changed()  -- cache miss, true
 
 s:select{1}
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 
 s:select{}
 stat_changed()  -- cache miss, true
 
 s:select{}
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 
 s:drop()
 
@@ -249,13 +251,13 @@ s:select{}
 stat_changed()  -- cache miss, true
 
 s:get{1, 2}
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 
 s:select{1}
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 
 s:select{}
-stat_changed() -- cache hit, false
+stat_changed() -- cache miss, true
 
 s:drop()
 
diff --git a/test/vinyl/errinj.result b/test/vinyl/errinj.result
index 31239ec0688b2b9cf07ed148b9d17eb36d0e6f0b..8aaa47457dc4a12e12ccd22a97c508b9fba6cd54 100644
--- a/test/vinyl/errinj.result
+++ b/test/vinyl/errinj.result
@@ -791,10 +791,12 @@ end;
 ---
 ...
 function iterate_in_read_view()
+    box.begin()
     local i = create_iterator(space)
     last_read = i.next()
     fiber.sleep(100000)
     last_read = i.next()
+    box.commit()
 end;
 ---
 ...
@@ -1149,6 +1151,9 @@ s:select{0}
 ---
 - - [0, 0]
 ...
+box.begin()
+---
+...
 errinj.set("ERRINJ_WAL_DELAY", true)
 ---
 - ok
@@ -1183,6 +1188,9 @@ value
 ---
 - [2, 0]
 ...
+box.commit()
+---
+...
 s:drop()
 ---
 ...
diff --git a/test/vinyl/errinj.test.lua b/test/vinyl/errinj.test.lua
index f3b3b7a24724f2c8782ec5782c5de77e20dda6ca..45eed72ebaaea596c20d7f13bbbb9b5562f88af2 100644
--- a/test/vinyl/errinj.test.lua
+++ b/test/vinyl/errinj.test.lua
@@ -309,10 +309,12 @@ function fill_space()
 end;
 
 function iterate_in_read_view()
+    box.begin()
     local i = create_iterator(space)
     last_read = i.next()
     fiber.sleep(100000)
     last_read = i.next()
+    box.commit()
 end;
 
 test_run:cmd("setopt delimiter ''");
@@ -450,6 +452,7 @@ box.snapshot()
 s:replace{0, 0}
 s:select{0}
 
+box.begin()
 errinj.set("ERRINJ_WAL_DELAY", true)
 wait_replace = true
 _ = fiber.create(function() s:replace{1, 1} wait_replace = false end)
@@ -460,4 +463,6 @@ errinj.set("ERRINJ_WAL_DELAY", false)
 while wait_replace do fiber.sleep(0.01) end
 state, value = gen(param, state)
 value
+box.commit()
+
 s:drop()
diff --git a/test/vinyl/iterator.result b/test/vinyl/iterator.result
index 4798f5f268117f74af3f085918d59a7ad0a30b2f..ceb59f10bd6e1c5129d5a0d080ef840318af1bfd 100644
--- a/test/vinyl/iterator.result
+++ b/test/vinyl/iterator.result
@@ -126,7 +126,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- []
+- 0: [1]
+  1: [2]
+  2: [3]
 ...
 --   3) create iterator within test case
 space:insert({1})
@@ -174,7 +176,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- []
+- 0: [1, 1]
+  1: [2, 2]
+  2: [3, 3]
 ...
 --
 -- UPSERT followed by DELETE
@@ -237,7 +241,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- []
+- 0: [1]
+  1: [2]
+  2: [3]
 ...
 --   3) create iterator within test case
 space:upsert({1}, {{'!', 2, 1}})
@@ -267,7 +273,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- []
+- 0: [3]
 ...
 --
 -- UPSERT followed by UPSERT
@@ -302,9 +308,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 1]
-  1: [2, 2]
-  2: [3, 3]
+- []
 ...
 space:truncate()
 ---
@@ -339,9 +343,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 1]
-  1: [2, 2]
-  2: [3, 3]
+- 0: [1]
+  1: [2]
+  2: [3]
 ...
 space:truncate()
 ---
@@ -377,8 +381,8 @@ space:select{}
 iterate_over(iter_obj)
 ---
 - 0: [1, 1]
-  1: [2, 2]
-  2: [3, 3]
+  1: [2]
+  2: [3]
 ...
 space:truncate()
 ---
@@ -419,9 +423,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 10]
-  1: [2, 20]
-  2: [3, 30]
+- []
 ...
 space:truncate()
 ---
@@ -459,9 +461,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 10]
-  1: [2, 20]
-  2: [3, 30]
+- 0: [1]
+  1: [2]
+  2: [3]
 ...
 space:truncate()
 ---
@@ -501,7 +503,7 @@ iterate_over(iter_obj)
 ---
 - 0: [1, 10]
   1: [2, 20]
-  2: [3, 30]
+  2: [3]
 ...
 space:truncate()
 ---
@@ -542,9 +544,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 1, 10]
-  1: [2, 2, 20]
-  2: [3, 3, 30]
+- []
 ...
 space:truncate()
 ---
@@ -582,9 +582,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 1, 10]
-  1: [2, 2, 20]
-  2: [3, 3, 30]
+- 0: [1, 10]
+  1: [2, 20]
+  2: [3, 30]
 ...
 space:truncate()
 ---
@@ -623,8 +623,8 @@ space:select{}
 iterate_over(iter_obj)
 ---
 - 0: [1, 1, 10]
-  1: [2, 2, 20]
-  2: [3, 3, 30]
+  1: [2, 20]
+  2: [3, 30]
 ...
 space:truncate()
 ---
@@ -696,7 +696,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- []
+- 0: [1, 10]
+  1: [2, 20]
+  2: [3, 30]
 ...
 --   3) create iterator within test case
 space:replace({1, 10})
@@ -729,7 +731,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- []
+- 0: [3, 30]
 ...
 --
 -- DELETE followed by REPLACE
@@ -779,9 +781,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1]
-  1: [2]
-  2: [3]
+- 0: [1, 10]
+  1: [2, 20]
+  2: [3, 30]
 ...
 space:truncate()
 ---
@@ -831,9 +833,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1]
-  1: [2]
-  2: [3]
+- []
 ...
 space:truncate()
 ---
@@ -885,7 +885,6 @@ iterate_over(iter_obj)
 ---
 - 0: [1]
   1: [2]
-  2: [3]
 ...
 space:truncate()
 ---
@@ -929,9 +928,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 10]
-  1: [2, 20]
-  2: [3, 30]
+- []
 ...
 space:truncate()
 ---
@@ -972,9 +969,9 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 10]
-  1: [2, 20]
-  2: [3, 30]
+- 0: [1]
+  1: [2]
+  2: [3]
 ...
 space:truncate()
 ---
@@ -1017,7 +1014,7 @@ iterate_over(iter_obj)
 ---
 - 0: [1, 10]
   1: [2, 20]
-  2: [3, 30]
+  2: [3]
 ...
 space:truncate()
 ---
@@ -1046,9 +1043,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1]
-  1: [2]
-  2: [3]
+- []
 ...
 space:truncate()
 ---
@@ -1075,8 +1070,6 @@ space:select{}
 iterate_over(iter_obj)
 ---
 - 0: [1]
-  1: [2]
-  2: [3]
 ...
 space:truncate()
 ---
@@ -1136,9 +1129,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1]
-  1: [2]
-  2: [3]
+- []
 ...
 space:truncate()
 ---
@@ -1169,7 +1160,6 @@ iterate_over(iter_obj)
 ---
 - 0: [1]
   1: [2]
-  2: [3]
 ...
 space:truncate()
 ---
@@ -1447,8 +1437,6 @@ box.snapshot()
 iterate_over(iter_obj_sp2)
 ---
 - 0: [5]
-  1: [6]
-  2: [8]
 ...
 space2:truncate()
 ---
@@ -1461,8 +1449,6 @@ iterate_over(iter_obj_sp3)
 ---
 - 0: [4]
   1: [5]
-  2: [6]
-  3: [8]
 ...
 space3:truncate()
 ---
@@ -1529,7 +1515,7 @@ space:select{}
 ...
 iterate_over(iter_obj)
 ---
-- 0: [1, 2, 3]
+- []
 ...
 iter_obj2 = create_iterator(idx2, 2, {iterator = 'EQ'})
 ---
@@ -1539,7 +1525,7 @@ space:delete({1})
 ...
 iterate_over(iter_obj2)
 ---
-- []
+- 0: [1, 2, 3]
 ...
 space:truncate()
 ---
@@ -1604,15 +1590,11 @@ space:select{}
 iterate_over(iter_obj)
 ---
 - 0: [3, 8, 1]
-  1: [4, 16, -1]
-  2: [5, 32, -10]
-  3: [6, 64, -10]
 ...
 iterate_over(iter_obj2)
 ---
 - 0: [4, 16, -1]
-  1: [6, 64, -10]
-  2: [5, 32, -10]
+  1: [5, 32, -10]
 ...
 iterate_over(iter_obj3)
 ---
@@ -1726,12 +1708,10 @@ iterate_over(iter_obj)
 ---
 - 0: [1, 1, 1]
   1: [2, 2, 2]
-  2: [3, 3, 3]
 ...
 iterate_over(iter_obj2)
 ---
 - 0: [2, 2, 2]
-  1: [3, 3, 3]
 ...
 box.commit()
 ---
diff --git a/test/vinyl/partial_dump.result b/test/vinyl/partial_dump.result
index 4f8fce224afbe2f83c976d3f1c43d3bb7821353b..b35335d18cff97e25955b51e1a971fd23ac60890 100644
--- a/test/vinyl/partial_dump.result
+++ b/test/vinyl/partial_dump.result
@@ -61,6 +61,20 @@ box.error.injection.set('ERRINJ_VY_INDEX_DUMP', -1)
 - ok
 ...
 test_run:cmd('restart server default')
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function tuple_equal(t1, t2)
+    if #t1 ~= #t2 then return false end
+    for i = 1, #t1 do
+        if t1[i] ~= t2[i] then return false end
+    end
+    return true
+end
+test_run:cmd("setopt delimiter ''");
+---
+...
 INDEX_COUNT = box.cfg.vinyl_write_threads * 3
 ---
 ...
@@ -91,7 +105,8 @@ for i = 1, INDEX_COUNT - 1 do
         bad_index = i
     end
     for _, v in s.index[i]:pairs() do
-        if v ~= s:get(v[1]) then
+        local v2 = s:get(v[1])
+        if not v2 or not tuple_equal(v, v2) then
             bad_index = i
         end
     end
diff --git a/test/vinyl/partial_dump.test.lua b/test/vinyl/partial_dump.test.lua
index 393f531fb01f131775c1d105627731cd61b590d9..87be87018d4e5bc24c25807f8c489c1cbdcd5dea 100644
--- a/test/vinyl/partial_dump.test.lua
+++ b/test/vinyl/partial_dump.test.lua
@@ -37,6 +37,16 @@ box.error.injection.set('ERRINJ_VY_INDEX_DUMP', -1)
 
 test_run:cmd('restart server default')
 
+test_run:cmd("setopt delimiter ';'")
+function tuple_equal(t1, t2)
+    if #t1 ~= #t2 then return false end
+    for i = 1, #t1 do
+        if t1[i] ~= t2[i] then return false end
+    end
+    return true
+end
+test_run:cmd("setopt delimiter ''");
+
 INDEX_COUNT = box.cfg.vinyl_write_threads * 3
 assert(INDEX_COUNT < 100)
 
@@ -50,7 +60,8 @@ for i = 1, INDEX_COUNT - 1 do
         bad_index = i
     end
     for _, v in s.index[i]:pairs() do
-        if v ~= s:get(v[1]) then
+        local v2 = s:get(v[1])
+        if not v2 or not tuple_equal(v, v2) then
             bad_index = i
         end
     end
diff --git a/test/vinyl/tx_gap_lock.result b/test/vinyl/tx_gap_lock.result
index 2a5087bf92bd003d412b02bfe13c52dbfdd3f797..425203c432a9c9080a3c9ced2144137cfd70efb9 100644
--- a/test/vinyl/tx_gap_lock.result
+++ b/test/vinyl/tx_gap_lock.result
@@ -1362,6 +1362,49 @@ test_run:cmd("setopt delimiter ''");
 - true
 ...
 ----------------------------------------------------------------
+-- gh-2534: Iterator doesn't track reads in autocommit mode.
+----------------------------------------------------------------
+s = box.schema.space.create('test', {engine = 'vinyl'})
+---
+...
+_ = s:create_index('pk', {parts = {1, 'unsigned'}})
+---
+...
+_ = s:create_index('sk', {parts = {2, 'unsigned'}})
+---
+...
+for i = 1, 100 do s:insert{i, i} end
+---
+...
+gen, param, state = s.index.sk:pairs()
+---
+...
+for i = 1, 100 do state, value = gen(param, state) end
+---
+...
+value
+---
+- [100, 100]
+...
+stat = box.info.vinyl()
+---
+...
+stat.tx.transactions -- 0
+---
+- 0
+...
+stat.tx.read_views -- 1
+---
+- 1
+...
+stat.tx.gap_locks -- 0
+---
+- 0
+...
+s:drop()
+---
+...
+----------------------------------------------------------------
 c = nil
 ---
 ...
diff --git a/test/vinyl/tx_gap_lock.test.lua b/test/vinyl/tx_gap_lock.test.lua
index 2343a719a153b86c3eb2e766aff26901dcbe3d74..b1b551d0d9349960109dbd61745a3fa3caaec248 100644
--- a/test/vinyl/tx_gap_lock.test.lua
+++ b/test/vinyl/tx_gap_lock.test.lua
@@ -507,6 +507,21 @@ s:drop();
 
 test_run:cmd("setopt delimiter ''");
 ----------------------------------------------------------------
+-- gh-2534: Iterator doesn't track reads in autocommit mode.
+----------------------------------------------------------------
+s = box.schema.space.create('test', {engine = 'vinyl'})
+_ = s:create_index('pk', {parts = {1, 'unsigned'}})
+_ = s:create_index('sk', {parts = {2, 'unsigned'}})
+for i = 1, 100 do s:insert{i, i} end
+gen, param, state = s.index.sk:pairs()
+for i = 1, 100 do state, value = gen(param, state) end
+value
+stat = box.info.vinyl()
+stat.tx.transactions -- 0
+stat.tx.read_views -- 1
+stat.tx.gap_locks -- 0
+s:drop()
+----------------------------------------------------------------
 
 c = nil
 c1 = nil