diff --git a/src/box/alter.cc b/src/box/alter.cc
index bc5415f4cc381ec3bf51437174fb01a995c0953a..60efb79ad07ff32cc8207a5ac6512a4bb8aedebb 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -2009,6 +2009,52 @@ filter_temporary_ddl_stmt(struct txn *txn, const struct space_def *def)
 	return 0;
 }
 
+/**
+ * Check whether @a old_space holders prohibit alter to @a new_space_def.
+ * For example if the space becomes temporary, there can be foreign keys
+ * from non-temporary space, so this alter must not be allowed.
+ * Return 0 if allowed, or -1 if not allowed (diag is set).
+ */
+static int
+space_check_alter(struct space *old_space, struct space_def *new_space_def)
+{
+	/*
+	 * group_id, which is currently used for defining local spaces, is
+	 * now can't be changed; if it could, an additional check would be
+	 * required below.
+	 */
+	assert(old_space->def->opts.group_id == new_space_def->opts.group_id);
+	/* Only alter from non-temporary to temporary can cause problems. */
+	if (old_space->def->opts.is_temporary ||
+	    !new_space_def->opts.is_temporary)
+		return 0;
+	/* Check for foreign keys that refers to this space. */
+	struct space_cache_holder *h;
+	rlist_foreach_entry(h, &old_space->space_cache_pin_list, link) {
+		if (h->selfpin)
+			continue;
+		if (h->type != SPACE_HOLDER_FOREIGN_KEY)
+			continue;
+		struct tuple_constraint *constr =
+			container_of(h, struct tuple_constraint,
+				     space_cache_holder);
+		struct space *other_space = constr->space;
+		/*
+		 * If the referring space is temporary too then the alter
+		 * can't break foreign key consistency after restart.
+		 */
+		if (other_space->def->opts.is_temporary)
+			continue;
+		diag_set(ClientError, ER_ALTER_SPACE,
+			 space_name(old_space),
+			 tt_sprintf("foreign key '%s' from non-temporary space"
+				    " '%s' can't refer to temporary space",
+				    constr->def.name, space_name(other_space)));
+		return -1;
+	}
+	return 0;
+}
+
 /**
  * A trigger which is invoked on replace in a data dictionary
  * space _space.