diff --git a/src/box/alter.cc b/src/box/alter.cc
index d6a41df9a1dbd667b87b7aec520e30e35bca464f..e342d1132a58e7aa53081efcb0fc7cff511d0de2 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -535,6 +535,12 @@ struct alter_space {
 	struct space *old_space;
 	/** New space. */
 	struct space *new_space;
+	/**
+	 * Assigned to the new primary key definition if we're
+	 * rebuilding the primary key, i.e. changing its key parts
+	 * substantially.
+	 */
+	struct key_def *pk_def;
 };
 
 struct alter_space *
@@ -1017,7 +1023,12 @@ class RebuildIndex: public AlterSpaceOp {
 		     struct index_def *old_index_def_arg)
 		:AlterSpaceOp(alter),
 		new_index_def(new_index_def_arg),
-		old_index_def(old_index_def_arg) {}
+		old_index_def(old_index_def_arg)
+	{
+		/* We may want to rebuild secondary keys as well. */
+		if (new_index_def->iid == 0)
+			alter->pk_def = new_index_def->key_def;
+	}
 	/** New index index_def. */
 	struct index_def *new_index_def;
 	/** Old index index_def. */
@@ -1108,10 +1119,29 @@ alter_space_move_indexes(struct alter_space *alter, uint32_t begin,
 {
 	struct space *old_space = alter->old_space;
 	for (uint32_t index_id = begin; index_id < end; ++index_id) {
-		Index *index = space_index(old_space, index_id);
-		if (index == NULL)
+		Index *old_index = space_index(old_space, index_id);
+		if (old_index == NULL)
 			continue;
-		(void) new MoveIndex(alter, index->index_def->iid);
+		struct index_def *old_def = old_index->index_def;
+		if (old_def->opts.is_unique || old_def->type != TREE ||
+		    alter->pk_def == NULL) {
+
+			(void) new MoveIndex(alter, old_def->iid);
+			continue;
+		}
+		/*
+		 * Rebuild non-unique secondary keys along with
+		 * the primary, since primary key parts have
+		 * changed.
+		 */
+		struct index_def *new_def =
+			index_def_new(old_def->space_id, old_def->iid,
+				      old_def->name, strlen(old_def->name),
+				      old_def->type, &old_def->opts,
+				      old_def->key_def, alter->pk_def);
+		auto guard = make_scoped_guard([=] { index_def_delete(new_def); });
+		(void) new RebuildIndex(alter, new_def, old_def);
+		guard.is_active = false;
 	}
 }
 
diff --git a/src/box/memtx_space.cc b/src/box/memtx_space.cc
index 077ec608503fe2e80810c0fd55ac47ac207e9c3c..fda15e04297f557168e0bdb49e8b0cac00469949 100644
--- a/src/box/memtx_space.cc
+++ b/src/box/memtx_space.cc
@@ -680,6 +680,11 @@ MemtxSpace::buildSecondaryKey(struct space *old_space,
 	}
 	Index *pk = index_find_xc(old_space, 0);
 
+	struct errinj *inj = errinj(ERRINJ_BUILD_SECONDARY, ERRINJ_INT);
+	if (inj != NULL && inj->iparam == (int)new_index->index_def->iid) {
+		tnt_raise(ClientError, ER_INJECTION, "buildSecondaryKey");
+	}
+
 	/* Now deal with any kind of add index during normal operation. */
 	struct iterator *it = pk->allocIterator();
 	IteratorGuard guard(it);
diff --git a/src/errinj.h b/src/errinj.h
index 298f444eb44e5d27d831402032d966bd208808b4..85a69765461505062717d44ac7e600fd9246fdb5 100644
--- a/src/errinj.h
+++ b/src/errinj.h
@@ -102,6 +102,7 @@ struct errinj {
 	_(ERRINJ_XLOG_READ, ERRINJ_INT, {.iparam = -1}) \
 	_(ERRINJ_VYRUN_INDEX_GARBAGE, ERRINJ_BOOL, {.bparam = false}) \
 	_(ERRINJ_VYRUN_DATA_READ, ERRINJ_BOOL, {.bparam = false}) \
+	_(ERRINJ_BUILD_SECONDARY, ERRINJ_INT, {.iparam = -1}) \
 
 ENUM0(errinj_id, ERRINJ_LIST);
 extern struct errinj errinjs[];
diff --git a/test/box/errinj.result b/test/box/errinj.result
index 7212bd0b7eaaf3f25db0a4349e588429902dc443..97ce7ee24fc7c18ea703822641cca334d152d3e6 100644
--- a/test/box/errinj.result
+++ b/test/box/errinj.result
@@ -16,6 +16,8 @@ errinj.info()
     state: false
   ERRINJ_WAL_WRITE:
     state: false
+  ERRINJ_BUILD_SECONDARY:
+    state: -1
   ERRINJ_VY_READ_PAGE_TIMEOUT:
     state: false
   ERRINJ_XLOG_META:
@@ -862,3 +864,125 @@ errinj.set("ERRINJ_WAL_WRITE", false)
 s:drop()
 ---
 ...
+-- rebuild some secondary indexes if the primary was changed
+s = box.schema.space.create('test')
+---
+...
+i1 = s:create_index('i1', {parts = {1, 'unsigned'}})
+---
+...
+--i2 = s:create_index('i2', {parts = {5, 'unsigned'}, unique = false})
+--i3 = s:create_index('i3', {parts = {6, 'unsigned'}, unique = false})
+i2 = i1 i3 = i1
+---
+...
+_ = s:insert{1, 4, 3, 4, 10, 10}
+---
+...
+_ = s:insert{2, 3, 1, 2, 10, 10}
+---
+...
+_ = s:insert{3, 2, 2, 1, 10, 10}
+---
+...
+_ = s:insert{4, 1, 4, 3, 10, 10}
+---
+...
+function sum(select_res) local r = 0 for _,t in pairs(select_res) do r = r + t[1] end return r end
+---
+...
+i1:select{}
+---
+- - [1, 4, 3, 4, 10, 10]
+  - [2, 3, 1, 2, 10, 10]
+  - [3, 2, 2, 1, 10, 10]
+  - [4, 1, 4, 3, 10, 10]
+...
+sum(i2:select{})
+---
+- 10
+...
+sum(i3:select{})
+---
+- 10
+...
+i1:alter({parts={2, 'unsigned'}})
+---
+...
+_ = collectgarbage('collect')
+---
+...
+i1:select{}
+---
+- - [4, 1, 4, 3, 10, 10]
+  - [3, 2, 2, 1, 10, 10]
+  - [2, 3, 1, 2, 10, 10]
+  - [1, 4, 3, 4, 10, 10]
+...
+sum(i2:select{})
+---
+- 10
+...
+sum(i3:select{})
+---
+- 10
+...
+box.error.injection.set('ERRINJ_BUILD_SECONDARY', i2.id)
+---
+- ok
+...
+i1:alter{parts = {3, "unsigned"}}
+---
+- error: Error injection 'buildSecondaryKey'
+...
+_ = collectgarbage('collect')
+---
+...
+i1:select{}
+---
+- - [4, 1, 4, 3, 10, 10]
+  - [3, 2, 2, 1, 10, 10]
+  - [2, 3, 1, 2, 10, 10]
+  - [1, 4, 3, 4, 10, 10]
+...
+sum(i2:select{})
+---
+- 10
+...
+sum(i3:select{})
+---
+- 10
+...
+box.error.injection.set('ERRINJ_BUILD_SECONDARY', i3.id)
+---
+- ok
+...
+i1:alter{parts = {4, "unsigned"}}
+---
+- error: Error injection 'buildSecondaryKey'
+...
+_ = collectgarbage('collect')
+---
+...
+i1:select{}
+---
+- - [4, 1, 4, 3, 10, 10]
+  - [3, 2, 2, 1, 10, 10]
+  - [2, 3, 1, 2, 10, 10]
+  - [1, 4, 3, 4, 10, 10]
+...
+sum(i2:select{})
+---
+- 10
+...
+sum(i3:select{})
+---
+- 10
+...
+box.error.injection.set('ERRINJ_BUILD_SECONDARY', -1)
+---
+- ok
+...
+s:drop()
+---
+...
diff --git a/test/box/errinj.test.lua b/test/box/errinj.test.lua
index cca3f5b04b3b1024e594e24906bcf809a062072b..97d4ac2d676f3847d2b20605e98b038804e7dcb7 100644
--- a/test/box/errinj.test.lua
+++ b/test/box/errinj.test.lua
@@ -285,3 +285,51 @@ _ = {fiber.create(test, {1, 2, 3}), fiber.create(test, {3, 4, 5})}
 {ch:get(), ch:get()}
 errinj.set("ERRINJ_WAL_WRITE", false)
 s:drop()
+
+-- rebuild some secondary indexes if the primary was changed
+s = box.schema.space.create('test')
+i1 = s:create_index('i1', {parts = {1, 'unsigned'}})
+--i2 = s:create_index('i2', {parts = {5, 'unsigned'}, unique = false})
+--i3 = s:create_index('i3', {parts = {6, 'unsigned'}, unique = false})
+i2 = i1 i3 = i1
+
+_ = s:insert{1, 4, 3, 4, 10, 10}
+_ = s:insert{2, 3, 1, 2, 10, 10}
+_ = s:insert{3, 2, 2, 1, 10, 10}
+_ = s:insert{4, 1, 4, 3, 10, 10}
+
+
+function sum(select_res) local r = 0 for _,t in pairs(select_res) do r = r + t[1] end return r end
+
+i1:select{}
+sum(i2:select{})
+sum(i3:select{})
+
+i1:alter({parts={2, 'unsigned'}})
+
+_ = collectgarbage('collect')
+i1:select{}
+sum(i2:select{})
+sum(i3:select{})
+
+box.error.injection.set('ERRINJ_BUILD_SECONDARY', i2.id)
+
+i1:alter{parts = {3, "unsigned"}}
+
+_ = collectgarbage('collect')
+i1:select{}
+sum(i2:select{})
+sum(i3:select{})
+
+box.error.injection.set('ERRINJ_BUILD_SECONDARY', i3.id)
+
+i1:alter{parts = {4, "unsigned"}}
+
+_ = collectgarbage('collect')
+i1:select{}
+sum(i2:select{})
+sum(i3:select{})
+
+box.error.injection.set('ERRINJ_BUILD_SECONDARY', -1)
+
+s:drop()