diff --git a/src/box/box.cc b/src/box/box.cc
index 32b08e3600686414b920430332714f18a87c63eb..4cf7dd13d0b12e078b2133aa69623bb59917f43b 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -741,6 +741,15 @@ box_set_vinyl_max_tuple_size(void)
 			cfg_geti("vinyl_max_tuple_size"));
 }
 
+void
+box_set_vinyl_cache(void)
+{
+	struct vinyl_engine *vinyl;
+	vinyl = (struct vinyl_engine *)engine_by_name("vinyl");
+	assert(vinyl != NULL);
+	vinyl_engine_set_cache(vinyl, cfg_geti64("vinyl_cache"));
+}
+
 void
 box_set_vinyl_timeout(void)
 {
@@ -1539,12 +1548,12 @@ engine_init()
 	struct vinyl_engine *vinyl;
 	vinyl = vinyl_engine_new_xc(cfg_gets("vinyl_dir"),
 				    cfg_geti64("vinyl_memory"),
-				    cfg_geti64("vinyl_cache"),
 				    cfg_geti("vinyl_read_threads"),
 				    cfg_geti("vinyl_write_threads"),
 				    cfg_geti("force_recovery"));
 	engine_register((struct engine *)vinyl);
 	box_set_vinyl_max_tuple_size();
+	box_set_vinyl_cache();
 	box_set_vinyl_timeout();
 }
 
diff --git a/src/box/box.h b/src/box/box.h
index 5c87da9d9ef7223514509153f989c0d3f0478658..baddcf73f00729ad0d9f2ffde7380b17c76ba033 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -171,6 +171,7 @@ void box_set_readahead(void);
 void box_set_checkpoint_count(void);
 void box_set_memtx_max_tuple_size(void);
 void box_set_vinyl_max_tuple_size(void);
+void box_set_vinyl_cache(void);
 void box_set_vinyl_timeout(void);
 void box_set_replication_timeout(void);
 void box_set_replication_connect_quorum(void);
diff --git a/src/box/lua/cfg.cc b/src/box/lua/cfg.cc
index be7c46929784a968eb8eb2cb2d9eb62a0729fc50..5e88ca348910abca78b03c9e2a57eeeb331cc7f3 100644
--- a/src/box/lua/cfg.cc
+++ b/src/box/lua/cfg.cc
@@ -198,6 +198,17 @@ lbox_cfg_set_vinyl_max_tuple_size(struct lua_State *L)
 	return 0;
 }
 
+static int
+lbox_cfg_set_vinyl_cache(struct lua_State *L)
+{
+	try {
+		box_set_vinyl_cache();
+	} catch (Exception *) {
+		luaT_error(L);
+	}
+	return 0;
+}
+
 static int
 lbox_cfg_set_vinyl_timeout(struct lua_State *L)
 {
@@ -259,6 +270,7 @@ box_lua_cfg_init(struct lua_State *L)
 		{"cfg_set_read_only", lbox_cfg_set_read_only},
 		{"cfg_set_memtx_max_tuple_size", lbox_cfg_set_memtx_max_tuple_size},
 		{"cfg_set_vinyl_max_tuple_size", lbox_cfg_set_vinyl_max_tuple_size},
+		{"cfg_set_vinyl_cache", lbox_cfg_set_vinyl_cache},
 		{"cfg_set_vinyl_timeout", lbox_cfg_set_vinyl_timeout},
 		{"cfg_set_replication_timeout", lbox_cfg_set_replication_timeout},
 		{"cfg_set_replication_connect_quorum",
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index 891d819d3c8c58f1f735c7406b79b835798451a0..d4f2128db5df6e931f26fa331e87ba8e0c22efcd 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -170,6 +170,7 @@ local dynamic_cfg = {
     read_only               = private.cfg_set_read_only,
     memtx_max_tuple_size    = private.cfg_set_memtx_max_tuple_size,
     vinyl_max_tuple_size    = private.cfg_set_vinyl_max_tuple_size,
+    vinyl_cache             = private.cfg_set_vinyl_cache,
     vinyl_timeout           = private.cfg_set_vinyl_timeout,
     checkpoint_count        = private.cfg_set_checkpoint_count,
     checkpoint_interval     = private.checkpoint_daemon.set_checkpoint_interval,
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index df518fcc151d624a2132999d6051762e4c6b605d..03a54670d3f6413babd8ff37ac554b4c9a3733e3 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -2625,7 +2625,7 @@ vy_squash_schedule(struct vy_index *index, struct tuple *stmt,
 		   void /* struct vy_env */ *arg);
 
 static struct vy_env *
-vy_env_new(const char *path, size_t memory, size_t cache,
+vy_env_new(const char *path, size_t memory,
 	   int read_threads, int write_threads, bool force_recovery)
 {
 	enum { KB = 1000, MB = 1000 * 1000 };
@@ -2700,7 +2700,7 @@ vy_env_new(const char *path, size_t memory, size_t cache,
 		      VY_QUOTA_UPDATE_INTERVAL);
 	e->quota_timer.data = e;
 	ev_timer_start(loop(), &e->quota_timer);
-	vy_cache_env_create(&e->cache_env, slab_cache, cache);
+	vy_cache_env_create(&e->cache_env, slab_cache);
 	vy_run_env_create(&e->run_env);
 	vy_log_init(e->path);
 	return e;
@@ -2742,7 +2742,7 @@ vy_env_delete(struct vy_env *e)
 }
 
 struct vinyl_engine *
-vinyl_engine_new(const char *dir, size_t memory, size_t cache,
+vinyl_engine_new(const char *dir, size_t memory,
 		 int read_threads, int write_threads, bool force_recovery)
 {
 	struct vinyl_engine *vinyl = calloc(1, sizeof(*vinyl));
@@ -2752,7 +2752,7 @@ vinyl_engine_new(const char *dir, size_t memory, size_t cache,
 		return NULL;
 	}
 
-	vinyl->env = vy_env_new(dir, memory, cache, read_threads,
+	vinyl->env = vy_env_new(dir, memory, read_threads,
 				write_threads, force_recovery);
 	if (vinyl->env == NULL) {
 		free(vinyl);
@@ -2772,6 +2772,12 @@ vinyl_engine_shutdown(struct engine *engine)
 	free(vinyl);
 }
 
+void
+vinyl_engine_set_cache(struct vinyl_engine *vinyl, size_t quota)
+{
+	vy_cache_env_set_quota(&vinyl->env->cache_env, quota);
+}
+
 void
 vinyl_engine_set_max_tuple_size(struct vinyl_engine *vinyl, size_t max_size)
 {
diff --git a/src/box/vinyl.h b/src/box/vinyl.h
index 63add146b60c8e73d448518b3aebf62b9927e429..ac7afefb6e17c930651c2bda9058d647245b6a87 100644
--- a/src/box/vinyl.h
+++ b/src/box/vinyl.h
@@ -42,7 +42,7 @@ struct info_handler;
 struct vinyl_engine;
 
 struct vinyl_engine *
-vinyl_engine_new(const char *dir, size_t memory, size_t cache,
+vinyl_engine_new(const char *dir, size_t memory,
 		 int read_threads, int write_threads, bool force_recovery);
 
 /**
@@ -51,6 +51,12 @@ vinyl_engine_new(const char *dir, size_t memory, size_t cache,
 void
 vinyl_engine_info(struct vinyl_engine *vinyl, struct info_handler *handler);
 
+/**
+ * Update vinyl cache size.
+ */
+void
+vinyl_engine_set_cache(struct vinyl_engine *vinyl, size_t quota);
+
 /**
  * Update max tuple size.
  */
@@ -76,11 +82,11 @@ vinyl_engine_set_too_long_threshold(struct vinyl_engine *vinyl,
 #include "diag.h"
 
 static inline struct vinyl_engine *
-vinyl_engine_new_xc(const char *dir, size_t memory, size_t cache,
+vinyl_engine_new_xc(const char *dir, size_t memory,
 		    int read_threads, int write_threads, bool force_recovery)
 {
 	struct vinyl_engine *vinyl;
-	vinyl = vinyl_engine_new(dir, memory, cache, read_threads,
+	vinyl = vinyl_engine_new(dir, memory, read_threads,
 				 write_threads, force_recovery);
 	if (vinyl == NULL)
 		diag_raise();
diff --git a/src/box/vy_cache.c b/src/box/vy_cache.c
index 6bededc130e624a55ffb62753ad94e3058fbfd38..1c3e3692a4d3fe11402cc723bdd156d9f3e506cd 100644
--- a/src/box/vy_cache.c
+++ b/src/box/vy_cache.c
@@ -30,6 +30,7 @@
  */
 #include "vy_cache.h"
 #include "diag.h"
+#include "fiber.h"
 #include "schema_def.h"
 
 #ifndef CT_ASSERT_G
@@ -51,12 +52,11 @@ enum {
 };
 
 void
-vy_cache_env_create(struct vy_cache_env *e, struct slab_cache *slab_cache,
-		    size_t mem_quota)
+vy_cache_env_create(struct vy_cache_env *e, struct slab_cache *slab_cache)
 {
 	rlist_create(&e->cache_lru);
 	e->mem_used = 0;
-	e->mem_quota = mem_quota;
+	e->mem_quota = 0;
 	mempool_create(&e->cache_entry_mempool, slab_cache,
 		       sizeof(struct vy_cache_entry));
 }
@@ -202,11 +202,30 @@ vy_cache_gc(struct vy_cache_env *env)
 	}
 }
 
+void
+vy_cache_env_set_quota(struct vy_cache_env *env, size_t quota)
+{
+	env->mem_quota = quota;
+	while (env->mem_used > env->mem_quota) {
+		vy_cache_gc(env);
+		/*
+		 * Make sure we don't block other tx fibers
+		 * for too long.
+		 */
+		fiber_sleep(0);
+	}
+}
+
 void
 vy_cache_add(struct vy_cache *cache, struct tuple *stmt,
 	     struct tuple *prev_stmt, const struct tuple *key,
 	     enum iterator_type order)
 {
+	if (cache->env->mem_quota == 0) {
+		/* Cache is disabled. */
+		return;
+	}
+
 	/* Delete some entries if quota overused */
 	vy_cache_gc(cache->env);
 
@@ -646,12 +665,6 @@ vy_cache_iterator_next(struct vy_cache_iterator *itr,
 	*ret = NULL;
 	*stop = false;
 
-	/* disable cache for errinj test - let it try to read from disk */
-	ERROR_INJECT(ERRINJ_VY_READ_PAGE,
-		     { itr->search_started = true; return; });
-	ERROR_INJECT(ERRINJ_VY_READ_PAGE_TIMEOUT,
-		     { itr->search_started = true; return; });
-
 	if (!itr->search_started) {
 		assert(itr->curr_stmt == NULL);
 		itr->search_started = true;
@@ -688,12 +701,6 @@ vy_cache_iterator_skip(struct vy_cache_iterator *itr,
 	*ret = NULL;
 	*stop = false;
 
-	/* disable cache for errinj test - let it try to read from disk */
-	ERROR_INJECT(ERRINJ_VY_READ_PAGE,
-		     { itr->search_started = true; return; });
-	ERROR_INJECT(ERRINJ_VY_READ_PAGE_TIMEOUT,
-		     { itr->search_started = true; return; });
-
 	assert(!itr->search_started || itr->version == itr->cache->version);
 
 	/*
@@ -756,16 +763,6 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr,
 			  const struct tuple *last_stmt,
 			  struct tuple **ret, bool *stop)
 {
-	/* disable cache for errinj test - let it try to read from disk */
-	if ((errinj(ERRINJ_VY_READ_PAGE, ERRINJ_BOOL) != NULL &&
-	     errinj(ERRINJ_VY_READ_PAGE, ERRINJ_BOOL)->bparam) ||
-	    (errinj(ERRINJ_VY_READ_PAGE_TIMEOUT, ERRINJ_BOOL) != NULL &&
-	     errinj(ERRINJ_VY_READ_PAGE_TIMEOUT, ERRINJ_BOOL)->bparam)) {
-		*ret = NULL;
-		*stop = false;
-		return 0;
-	}
-
 	struct key_def *def = itr->cache->cmp_def;
 	int dir = iterator_direction(itr->iterator_type);
 
diff --git a/src/box/vy_cache.h b/src/box/vy_cache.h
index d4e213db972db3a885e8aed808c170d810f1461f..fceda5a216fa9a6374d2c323ee92db054647563a 100644
--- a/src/box/vy_cache.h
+++ b/src/box/vy_cache.h
@@ -127,11 +127,9 @@ struct vy_cache_env {
  * Initialize common cache environment.
  * @param e - the environment.
  * @param slab_cache - source of memory.
- * @param mem_quota - memory limit for the cache.
  */
 void
-vy_cache_env_create(struct vy_cache_env *env, struct slab_cache *slab_cache,
-		    size_t mem_quota);
+vy_cache_env_create(struct vy_cache_env *env, struct slab_cache *slab_cache);
 
 /**
  * Destroy and free resources of cache environment.
@@ -140,6 +138,17 @@ vy_cache_env_create(struct vy_cache_env *env, struct slab_cache *slab_cache,
 void
 vy_cache_env_destroy(struct vy_cache_env *e);
 
+/**
+ * Set memory limit for the cache.
+ * @param e - the environment.
+ * @param quota - memory limit for the cache.
+ *
+ * This function blocks until it manages to free enough memory
+ * to fit in the new limit.
+ */
+void
+vy_cache_env_set_quota(struct vy_cache_env *e, size_t quota);
+
 /**
  * Tuple cache (of one particular index)
  */
diff --git a/test/unit/vy_iterators_helper.c b/test/unit/vy_iterators_helper.c
index a35f4ef9a89e352fc1fb06e19f9f3e5ac676a3cd..0e41de4b1dab85e212e0ac356d8bcceca6145c56 100644
--- a/test/unit/vy_iterators_helper.c
+++ b/test/unit/vy_iterators_helper.c
@@ -19,7 +19,8 @@ vy_iterator_C_test_init(size_t cache_size)
 	memory_init();
 	fiber_init(fiber_c_invoke);
 	tuple_init(NULL);
-	vy_cache_env_create(&cache_env, cord_slab_cache(), cache_size);
+	vy_cache_env_create(&cache_env, cord_slab_cache());
+	vy_cache_env_set_quota(&cache_env, cache_size);
 	vy_key_format = tuple_format_new(&vy_tuple_format_vtab, NULL, 0, 0,
 					 NULL, 0, NULL);
 	tuple_format_ref(vy_key_format);
diff --git a/test/unit/vy_point_lookup.c b/test/unit/vy_point_lookup.c
index 0cc8dc223f8631c113be9e4fcc33c69dbb3caf41..52f4427e97b5eed0eff9f56db5ec1a0e766c714f 100644
--- a/test/unit/vy_point_lookup.c
+++ b/test/unit/vy_point_lookup.c
@@ -71,7 +71,8 @@ test_basic()
 	vy_run_env_create(&run_env);
 
 	struct vy_cache_env cache_env;
-	vy_cache_env_create(&cache_env, slab_cache, QUOTA);
+	vy_cache_env_create(&cache_env, slab_cache);
+	vy_cache_env_set_quota(&cache_env, QUOTA);
 
 	struct vy_cache cache;
 	uint32_t fields[] = { 0 };
diff --git a/test/vinyl/cache.result b/test/vinyl/cache.result
index 117eff052f7c29db3afd53103a315c22a6df28cc..b4812297360fa89bf4d2b692828891174bc2b407 100644
--- a/test/vinyl/cache.result
+++ b/test/vinyl/cache.result
@@ -1012,3 +1012,70 @@ pk:info().disk.iterator.lookup
 s:drop()
 ---
 ...
+--
+-- Cache resize
+--
+vinyl_cache = box.cfg.vinyl_cache
+---
+...
+box.cfg{vinyl_cache = 1000 * 1000}
+---
+...
+s = box.schema.space.create('test', {engine = 'vinyl'})
+---
+...
+_ = s:create_index('pk')
+---
+...
+for i = 1, 100 do s:replace{i, string.rep('x', 1000)} end
+---
+...
+for i = 1, 100 do s:get{i} end
+---
+...
+box.info.vinyl().cache.used
+---
+- 107700
+...
+box.cfg{vinyl_cache = 50 * 1000}
+---
+...
+box.info.vinyl().cache.used
+---
+- 49542
+...
+box.cfg{vinyl_cache = 0}
+---
+...
+box.info.vinyl().cache.used
+---
+- 0
+...
+-- Make sure cache is not populated if box.cfg.vinyl_cache is set to 0
+st1 = s.index.pk:info().cache
+---
+...
+#s:select()
+---
+- 100
+...
+for i = 1, 100 do s:get{i} end
+---
+...
+st2 = s.index.pk:info().cache
+---
+...
+st2.put.rows - st1.put.rows
+---
+- 0
+...
+box.info.vinyl().cache.used
+---
+- 0
+...
+s:drop()
+---
+...
+box.cfg{vinyl_cache = vinyl_cache}
+---
+...
diff --git a/test/vinyl/cache.test.lua b/test/vinyl/cache.test.lua
index 9478a442e8e0d26bfdca8f643b88fbb24a1e56f0..9ff77cbb91fe996188b7c9e682ff3e5cb0e8b4b3 100644
--- a/test/vinyl/cache.test.lua
+++ b/test/vinyl/cache.test.lua
@@ -358,3 +358,27 @@ info.lookup
 info.get.rows
 pk:info().disk.iterator.lookup
 s:drop()
+
+--
+-- Cache resize
+--
+vinyl_cache = box.cfg.vinyl_cache
+box.cfg{vinyl_cache = 1000 * 1000}
+s = box.schema.space.create('test', {engine = 'vinyl'})
+_ = s:create_index('pk')
+for i = 1, 100 do s:replace{i, string.rep('x', 1000)} end
+for i = 1, 100 do s:get{i} end
+box.info.vinyl().cache.used
+box.cfg{vinyl_cache = 50 * 1000}
+box.info.vinyl().cache.used
+box.cfg{vinyl_cache = 0}
+box.info.vinyl().cache.used
+-- Make sure cache is not populated if box.cfg.vinyl_cache is set to 0
+st1 = s.index.pk:info().cache
+#s:select()
+for i = 1, 100 do s:get{i} end
+st2 = s.index.pk:info().cache
+st2.put.rows - st1.put.rows
+box.info.vinyl().cache.used
+s:drop()
+box.cfg{vinyl_cache = vinyl_cache}