diff --git a/mysql-test/suite/innodb/r/alter_varchar_change.result b/mysql-test/suite/innodb/r/alter_varchar_change.result
new file mode 100644
index 0000000..9d8ad40
--- /dev/null
+++ b/mysql-test/suite/innodb/r/alter_varchar_change.result
@@ -0,0 +1,246 @@
+CREATE PROCEDURE get_index_id(IN tbl_id INT, IN idx_name char(100), OUT idx_id INT)
+BEGIN
+SELECT index_id into idx_id FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE
+NAME=idx_name and TABLE_ID=tbl_id;
+END|
+CREATE PROCEDURE get_table_id(IN tbl_name char(100), OUT tbl_id INT)
+BEGIN
+SELECT table_id into tbl_id FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE
+NAME = tbl_name;
+END|
+SET @tbl_id = 0;
+SET @tbl1_id = 0;
+SET @idx_id = 0;
+SET @idx1_id = 0;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+0
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) NOT NULL,
+  PRIMARY KEY (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 VARCHAR(100),
+INDEX idx(f2))ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+0
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) DEFAULT NULL,
+  KEY `idx` (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100), f3 VARCHAR(100),
+INDEX idx(f2, f3), index idx1(f3, f2))ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), MODIFY f3 VARCHAR(150);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+0
+SELECT @idx1_id - @idx_id;
+@idx1_id - @idx_id
+0
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) DEFAULT NULL,
+  `f3` varchar(150) DEFAULT NULL,
+  KEY `idx` (`f2`,`f3`),
+  KEY `idx1` (`f3`,`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100),
+INDEX idx(f2(40)))ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+0
+SELECT @idx1_id - @idx_id;
+@idx1_id - @idx_id
+0
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) DEFAULT NULL,
+  KEY `idx` (`f2`(40))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 VARCHAR(100), FULLTEXT idx(f2))ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+0
+SELECT @idx1_id - @idx_id;
+@idx1_id - @idx_id
+0
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) DEFAULT NULL,
+  FULLTEXT KEY `idx` (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 VARCHAR(100),
+f3 VARCHAR(50) as (f2) VIRTUAL,
+INDEX idx(f3))ENGINE=InnoDB;
+INSERT INTO t1(f1, f2) VALUES(1, repeat('a', 40));
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(100);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+0
+SELECT @idx1_id - @idx_id;
+@idx1_id - @idx_id
+0
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(100) DEFAULT NULL,
+  `f3` varchar(50) GENERATED ALWAYS AS (`f2`) VIRTUAL,
+  KEY `idx` (`f3`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 VARCHAR(100),
+INDEX idx(f2(100)))ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD INDEX idx1(f1);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+0
+SELECT @idx1_id - @idx_id;
+@idx1_id - @idx_id
+0
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) DEFAULT NULL,
+  KEY `idx` (`f2`),
+  KEY `idx1` (`f1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 VARCHAR(100),
+INDEX idx(f2))ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
+CALL get_table_id("test/t1", @tbl1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+1
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) DEFAULT NULL,
+  `f3` int(11) DEFAULT NULL,
+  KEY `idx` (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
+CALL get_table_id("test/t1", @tbl1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+1
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) NOT NULL,
+  `f3` int(11) DEFAULT NULL,
+  PRIMARY KEY (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100))ENGINE=INNODB;
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD FULLTEXT idx(f2);
+Warnings:
+Warning	124	InnoDB rebuilding table to add column FTS_DOC_ID
+CALL get_table_id("test/t1", @tbl1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+1
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(200) DEFAULT NULL,
+  FULLTEXT KEY `idx` (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 CHAR(100) PRIMARY KEY)ENGINE=InnoDB;
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 CHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+SELECT @tbl1_id - @tbl_id;
+@tbl1_id - @tbl_id
+1
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` char(200) NOT NULL,
+  PRIMARY KEY (`f2`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(f1 INT NOT NULL,
+f2 VARCHAR(100),
+f3 VARCHAR(50) as (f2) VIRTUAL,
+INDEX idx(f3))ENGINE=InnoDB;
+# If varchar virtual column extension is allowed in the future then
+#	InnoDB must rebuild the index
+ALTER TABLE t1 MODIFY f3 VARCHAR(100);
+ERROR HY000: This is not yet supported for generated columns
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `f1` int(11) NOT NULL,
+  `f2` varchar(100) DEFAULT NULL,
+  `f3` varchar(50) GENERATED ALWAYS AS (`f2`) VIRTUAL,
+  KEY `idx` (`f3`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+DROP PROCEDURE get_index_id;
+DROP PROCEDURE get_table_id;
diff --git a/mysql-test/suite/innodb/r/innodb-index-online.result b/mysql-test/suite/innodb/r/innodb-index-online.result
index 3134c64..630e878 100644
--- a/mysql-test/suite/innodb/r/innodb-index-online.result
+++ b/mysql-test/suite/innodb/r/innodb-index-online.result
@@ -227,7 +227,7 @@ WHERE variable_name = 'innodb_encryption_n_rowlog_blocks_encrypted');
 connection con1;
 SET DEBUG_SYNC = 'row_log_apply_before SIGNAL c2e_created WAIT_FOR dml2_done';
 SET lock_wait_timeout = 10;
-ALTER TABLE t1 DROP INDEX c2d, ADD INDEX c2e(c2),
+ALTER TABLE t1 CHANGE c2 c22 INT, DROP INDEX c2d, ADD INDEX c2e(c22, c3(10)),
 ALGORITHM = INPLACE;
 connection default;
 INSERT INTO t1 SELECT  80 + c1, c2, c3 FROM t1;
@@ -286,6 +286,7 @@ INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_FIELDS sf
 ON si.index_id = sf.index_id WHERE si.name = '?c2e';
 name	pos
 c2	0
+c3	1
 SET @merge_encrypt_1=
 (SELECT variable_value FROM information_schema.global_status
 WHERE variable_name = 'innodb_encryption_n_merge_blocks_encrypted');
diff --git a/mysql-test/suite/innodb/t/alter_varchar_change.test b/mysql-test/suite/innodb/t/alter_varchar_change.test
new file mode 100644
index 0000000..15e5afd
--- /dev/null
+++ b/mysql-test/suite/innodb/t/alter_varchar_change.test
@@ -0,0 +1,188 @@
+--source include/have_innodb.inc
+
+DELIMITER |;
+CREATE PROCEDURE get_index_id(IN tbl_id INT, IN idx_name char(100), OUT idx_id INT)
+BEGIN
+SELECT index_id into idx_id FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE
+	NAME=idx_name and TABLE_ID=tbl_id;
+END|
+
+CREATE PROCEDURE get_table_id(IN tbl_name char(100), OUT tbl_id INT)
+BEGIN
+SELECT table_id into tbl_id FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE
+	NAME = tbl_name;
+END|
+
+DELIMITER ;|
+
+SET @tbl_id = 0;
+SET @tbl1_id = 0;
+SET @idx_id = 0;
+SET @idx1_id = 0;
+
+# Table should avoid rebuild for the following varchar change.
+
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+# Index should avoid rebuild
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 VARCHAR(100),
+		INDEX idx(f2))ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100), f3 VARCHAR(100),
+		INDEX idx(f2, f3), index idx1(f3, f2))ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), MODIFY f3 VARCHAR(150);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SELECT @idx1_id - @idx_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100),
+		INDEX idx(f2(40)))ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SELECT @idx1_id - @idx_id;
+
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 VARCHAR(100), FULLTEXT idx(f2))ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SELECT @idx1_id - @idx_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 VARCHAR(100),
+		f3 VARCHAR(50) as (f2) VIRTUAL,
+		INDEX idx(f3))ENGINE=InnoDB;
+
+INSERT INTO t1(f1, f2) VALUES(1, repeat('a', 40));
+
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(100);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SELECT @idx1_id - @idx_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+# Newly added index should built
+
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 VARCHAR(100),
+		INDEX idx(f2(100)))ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+CALL get_index_id(@tbl_id, "idx", @idx_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD INDEX idx1(f1);
+CALL get_table_id("test/t1", @tbl1_id);
+CALL get_index_id(@tbl1_id, "idx", @idx1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SELECT @idx1_id - @idx_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+# Table should rebuild
+
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 VARCHAR(100),
+		INDEX idx(f2))ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
+CALL get_table_id("test/t1", @tbl1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100) PRIMARY KEY)ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD COLUMN f3 INT;
+CALL get_table_id("test/t1", @tbl1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1(f1 INT NOT NULL, f2 VARCHAR(100))ENGINE=INNODB;
+
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 VARCHAR(200), ADD FULLTEXT idx(f2);
+CALL get_table_id("test/t1", @tbl1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 CHAR(100) PRIMARY KEY)ENGINE=InnoDB;
+
+CALL get_table_id("test/t1", @tbl_id);
+ALTER TABLE t1 MODIFY f2 CHAR(200);
+CALL get_table_id("test/t1", @tbl1_id);
+
+SELECT @tbl1_id - @tbl_id;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+# Show error when virtual varchar column got changed
+
+CREATE TABLE t1(f1 INT NOT NULL,
+		f2 VARCHAR(100),
+		f3 VARCHAR(50) as (f2) VIRTUAL,
+		INDEX idx(f3))ENGINE=InnoDB;
+
+--echo # If varchar virtual column extension is allowed in the future then
+--echo #	InnoDB must rebuild the index
+
+--error ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN
+ALTER TABLE t1 MODIFY f3 VARCHAR(100);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+DROP PROCEDURE get_index_id;
+DROP PROCEDURE get_table_id;
diff --git a/mysql-test/suite/innodb/t/innodb-index-online.test b/mysql-test/suite/innodb/t/innodb-index-online.test
index efe1c79..24a12d9 100644
--- a/mysql-test/suite/innodb/t/innodb-index-online.test
+++ b/mysql-test/suite/innodb/t/innodb-index-online.test
@@ -221,9 +221,7 @@ SET DEBUG_SYNC = 'row_log_apply_before SIGNAL c2e_created WAIT_FOR dml2_done';
 # Ensure that the ALTER TABLE will be executed even with some concurrent DML.
 SET lock_wait_timeout = 10;
 --send
-# FIXME: MDEV-13668
-#ALTER TABLE t1 CHANGE c2 c22 INT, DROP INDEX c2d, ADD INDEX c2e(c22),
-ALTER TABLE t1 DROP INDEX c2d, ADD INDEX c2e(c2),
+ALTER TABLE t1 CHANGE c2 c22 INT, DROP INDEX c2d, ADD INDEX c2e(c22, c3(10)),
 ALGORITHM = INPLACE;
 
 # Generate some log (delete-mark, delete-unmark, insert etc.)
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index c55850d..128645b 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -115,6 +115,26 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_NOREBUILD
 	| Alter_inplace_info::DROP_VIRTUAL_COLUMN
 	| Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER;
 
+/** Operations that InnoDB does drop index and re-create the same index */
+static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_NON_UNIQ_INDEX_RECREATE
+	= Alter_inplace_info::DROP_INDEX
+	| Alter_inplace_info::ADD_INDEX;
+
+static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_UNIQ_INDEX_RECREATE
+	= Alter_inplace_info::DROP_UNIQUE_INDEX
+	| Alter_inplace_info::ADD_UNIQUE_INDEX;
+
+static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_PRIM_INDEX_RECREATE
+	= Alter_inplace_info::ADD_PK_INDEX
+	  | Alter_inplace_info::DROP_PK_INDEX;
+
+/** Structure to store the old index name and new index name */
+struct index_name_pair
+{
+	char*	old_idx_name;
+	char*	new_idx_name;
+};
+
 struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
 {
 	/** Dummy query graph */
@@ -179,6 +199,18 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
 	const char**	drop_vcol_name;
 	/** ALTER TABLE stage progress recorder */
 	ut_stage_alter_t* m_stage;
+	/** List of key number to be ignored for add index */
+	ulint*		ignore_add_keys;
+	/** List of key number to be ignored for drop index */
+	ulint*		ignore_drop_keys;
+	/** Number of ignore keys */
+	ulint		num_to_ignore_keys;
+	/** Ignore all keys */
+	bool		ignore_all_keys;
+	/** Rename index */
+	index_name_pair* rename_indexes;
+	/** Number of rename index */
+	ulint		num_rename_index;
 
 	ha_innobase_inplace_ctx(row_prebuilt_t*& prebuilt_arg,
 				dict_index_t** drop_arg,
@@ -196,7 +228,13 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
 				ulint add_autoinc_arg,
 				ulonglong autoinc_col_min_value_arg,
 				ulonglong autoinc_col_max_value_arg,
-				ulint num_to_drop_vcol_arg) :
+				ulint num_to_drop_vcol_arg,
+				ulint* ignore_add_keys_arg,
+				ulint* ignore_drop_keys_arg,
+				ulint  num_to_ignore_keys_arg,
+				bool ignore_all_keys_arg,
+				index_name_pair* rename_indexes_arg,
+				ulint num_rename_index_arg):
 		inplace_alter_handler_ctx(),
 		prebuilt (prebuilt_arg),
 		add_index (0), add_key_numbers (0), num_to_add_index (0),
@@ -220,7 +258,13 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
 		num_to_drop_vcol(0),
 		drop_vcol(0),
 		drop_vcol_name(0),
-		m_stage(NULL)
+		m_stage(NULL),
+		ignore_add_keys(ignore_add_keys_arg),
+		ignore_drop_keys(ignore_drop_keys_arg),
+		num_to_ignore_keys(num_to_ignore_keys_arg),
+		ignore_all_keys(ignore_all_keys_arg),
+		rename_indexes(rename_indexes_arg),
+		num_rename_index(num_rename_index_arg)
 	{
 #ifdef UNIV_DEBUG
 		for (ulint i = 0; i < num_to_add_index; i++) {
@@ -255,6 +299,27 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
 		}
 	}
 
+	/** Determine if the primary index can be ignored.
+	@return whether the primary index ignored */
+	bool is_ignore_pk_index(Alter_inplace_info* ha_alter_info) const {
+		if (num_to_ignore_keys == 0) {
+			return false;
+		}
+
+		for (ulint i = 0; i < num_to_ignore_keys; i++) {
+			ulint add_offset = ha_alter_info->index_add_buffer[
+						ignore_add_keys[i]];
+			if (!my_strcasecmp(
+				system_charset_info,
+				ha_alter_info->key_info_buffer[add_offset].name,
+				"PRIMARY")) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
 private:
 	// Disable copying
 	ha_innobase_inplace_ctx(const ha_innobase_inplace_ctx&);
@@ -419,12 +484,14 @@ innobase_spatial_exist(
 /** Determine if ALTER TABLE needs to rebuild the table.
 @param ha_alter_info	the DDL operation
 @param table		metadata before ALTER TABLE
+@param ignore_pk	ignore pk index
 @return whether it is necessary to rebuild the table */
 static MY_ATTRIBUTE((nonnull, warn_unused_result))
 bool
 innobase_need_rebuild(
 	const Alter_inplace_info*	ha_alter_info,
-	const TABLE*			table)
+	const TABLE*			table,
+	bool				ignore_pk=false)
 {
 	Alter_inplace_info::HA_ALTER_FLAGS alter_inplace_flags =
 		ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE;
@@ -453,6 +520,12 @@ innobase_need_rebuild(
 		return(false);
 	}
 
+	if (ignore_pk) {
+		return !!(alter_inplace_flags
+			  & (INNOBASE_ALTER_REBUILD
+			     & ~INNOBASE_PRIM_INDEX_RECREATE));
+	}
+
 	return(!!(alter_inplace_flags & INNOBASE_ALTER_REBUILD));
 }
 
@@ -2508,48 +2581,66 @@ innobase_fts_check_doc_id_index_in_def(
 	return(FTS_NOT_EXIST_DOC_ID_INDEX);
 }
 
-/*******************************************************************//**
-Create an index table where indexes are ordered as follows:
+/** Check whether the given key number is a part of ignore keys.
+@param[in]	ignore_keys	list of keys to be ignored
+@param[in]	num_pos		number of keys to be ignored
+@param[in]	pos		key number to be searched in ignore keys
+@return key number is a part of ignore keys. */
+static bool is_ignore_key(const ulint* ignore_keys, ulint num_pos, const ulint pos)
+{
+	if (num_pos == 0) {
+		return false;
+	}
 
-IF a new primary key is defined for the table THEN
+	for (ulint i = 0; i < num_pos; i++) {
+		if (ignore_keys[i] == pos) {
+			return true;
+		}
+	}
 
+	return false;
+}
+
+/** Create an index table expect the indexes in ignore list
+where indexes are ordered as follows:
+IF a new primary key is defined for the table THEN
 	1) New primary key
 	2) The remaining keys in key_info
 
 ELSE
-
 	1) All new indexes in the order they arrive from MySQL
-
 ENDIF
-
+@param[in,out]	heap			memory heap where space for
+					key definitions are allocated
+@param[in]	ha_alter_info		Alter operation
+@param[in]	altered_table		MySQL table that is being altered
+@param[in,out]	n_add			number of indexes to be created
+@param[out]	n_fts_add		number of FTS indexes to be created
+@param[in]	got_default_clust	whether the table lacks a primary key
+@param[in]	fts_doc_id_col		Column number for Doc ID
+@param]in]	add_fts_doc_id		Whether we need to add new DOC ID
+					column for FTS index
+@param[in]	add_fts_doc_idx		Whether we need to add new DOC ID
+					index for FTS index
+@param[in]	table			MySQL table that is being altered
+@param[in]	ignore_add_keys		Keys to be ignored during add index
+@param[in]	num_to_ignore_keys	Number of keys to be ignored
 @return key definitions */
 static MY_ATTRIBUTE((nonnull, warn_unused_result, malloc))
 index_def_t*
 innobase_create_key_defs(
-/*=====================*/
 	mem_heap_t*			heap,
-			/*!< in/out: memory heap where space for key
-			definitions are allocated */
 	const Alter_inplace_info*	ha_alter_info,
-			/*!< in: alter operation */
 	const TABLE*			altered_table,
-			/*!< in: MySQL table that is being altered */
 	ulint&				n_add,
-			/*!< in/out: number of indexes to be created */
 	ulint&				n_fts_add,
-			/*!< out: number of FTS indexes to be created */
 	bool				got_default_clust,
-			/*!< in: whether the table lacks a primary key */
 	ulint&				fts_doc_id_col,
-			/*!< in: The column number for Doc ID */
 	bool&				add_fts_doc_id,
-			/*!< in: whether we need to add new DOC ID
-			column for FTS index */
 	bool&				add_fts_doc_idx,
-			/*!< in: whether we need to add new DOC ID
-			index for FTS index */
-	const TABLE*			table)
-			/*!< in: MySQL table that is being altered */
+	const TABLE*			table,
+	const ulint*			ignore_add_keys,
+	ulint				num_to_ignore_keys)
 {
 	index_def_t*		indexdef;
 	index_def_t*		indexdefs;
@@ -2561,14 +2652,20 @@ innobase_create_key_defs(
 
 	DBUG_ENTER("innobase_create_key_defs");
 	DBUG_ASSERT(!add_fts_doc_id || add_fts_doc_idx);
-	DBUG_ASSERT(ha_alter_info->index_add_count == n_add);
+	DBUG_ASSERT(ha_alter_info->index_add_count
+		    == n_add + num_to_ignore_keys);
 
 	/* If there is a primary key, it is always the first index
 	defined for the innodb_table. */
 
+	bool	ignore_pk = is_ignore_key(
+			ignore_add_keys, num_to_ignore_keys, *add);
+
 	new_primary = n_add > 0
 		&& !my_strcasecmp(system_charset_info,
-				  key_info[*add].name, "PRIMARY");
+				  key_info[*add].name, "PRIMARY")
+		&& !ignore_pk;
+
 	n_fts_add = 0;
 
 	/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
@@ -2584,18 +2681,17 @@ innobase_create_key_defs(
 	}
 
 	const bool rebuild = new_primary || add_fts_doc_id
-		|| innobase_need_rebuild(ha_alter_info, table);
-
-	/* Reserve one more space if new_primary is true, and we might
-	need to add the FTS_DOC_ID_INDEX */
-	indexdef = indexdefs = static_cast<index_def_t*>(
-		mem_heap_alloc(
-			heap, sizeof *indexdef
-			* (ha_alter_info->key_count
-			   + rebuild
-			   + got_default_clust)));
+			     || innobase_need_rebuild(
+					ha_alter_info, table, ignore_pk);
 
 	if (rebuild) {
+		indexdef = indexdefs = static_cast<index_def_t*>(
+			mem_heap_alloc(
+				heap, sizeof *indexdef
+				* (ha_alter_info->key_count
+				   + rebuild
+				   + got_default_clust)));
+
 		ulint	primary_key_number;
 
 		if (new_primary) {
@@ -2676,15 +2772,37 @@ innobase_create_key_defs(
 	} else {
 		/* Create definitions for added secondary indexes. */
 
-		for (ulint i = 0; i < n_add; i++) {
+		indexdef = indexdefs = static_cast<index_def_t*>(
+				mem_heap_alloc(
+					heap, sizeof *indexdef
+					* ((ha_alter_info->key_count
+					    - num_to_ignore_keys)
+					   + got_default_clust)));
+
+		ulint	key_pos = 0;
+		ulint	n_index = 0;
+
+		while (1) {
+			if (n_index == n_add) {
+				break;
+			}
+
+			for (ulint i = 0; i < num_to_ignore_keys; i++) {
+				if (ignore_add_keys[i] == key_pos) {
+					key_pos++;
+				}
+			}
+
 			innobase_create_index_def(
-				altered_table, key_info, add[i],
+				altered_table, key_info, add[key_pos],
 				false, false, indexdef, heap);
 
 			if (indexdef->ind_type & DICT_FTS) {
 				n_fts_add++;
 			}
 
+			n_index++;
+			key_pos++;
 			indexdef++;
 		}
 	}
@@ -2717,7 +2835,8 @@ innobase_create_key_defs(
 	DBUG_ASSERT((ulint) (indexdef - indexdefs)
 		    <= ha_alter_info->key_count
 		    + add_fts_doc_idx + got_default_clust);
-	DBUG_ASSERT(ha_alter_info->index_add_count <= n_add);
+	DBUG_ASSERT(ha_alter_info->index_add_count
+		    <= n_add + num_to_ignore_keys);
 	DBUG_RETURN(indexdefs);
 }
 
@@ -3200,6 +3319,188 @@ innobase_drop_fts_index_table(
 	return(ret_err);
 }
 
+/** Get the field for the given field number
+@param[in]	alter_info	Data used during inplace alter
+@param[in]	field_no	field number to get field
+@return field from create list of an alter info. */
+static Create_field* get_field_by_field_no(
+	Alter_info*	alter_info,
+	ulint		idx)
+{
+	List_iterator_fast<Create_field> field_it(alter_info->create_list);
+	uint	field_idx = 0;
+	Create_field*	field;
+
+	while ((field = field_it++) && field_idx < idx) {
+		field_idx++;
+	}
+
+	return field;
+}
+
+/** Check whether the name is a part of drop key names.
+@param[in]	ha_alter_info	Data used during inplace alter
+@param[in]	name		name to be searched
+@return true if name is found in the drop key names. */
+static bool innobase_check_drop_key_name(
+	Alter_inplace_info*	ha_alter_info,
+	const char*		name)
+{
+	for (ulint i = 0; i < ha_alter_info->index_drop_count; i++) {
+		const KEY* drop_key = ha_alter_info->index_drop_buffer[i];
+
+		if (strcmp(drop_key->name, name) == 0) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/** Check whether the key rebuild happens because of extending varchar column
+changes.
+@param[in]	ha_alter_info	Data used during inplace alter
+@param[in]	new_key		new key to be build
+@param[in]	old_key		old key to be build
+@return whether key rebuild happened because of extend varchar column. */
+static bool innobase_check_key_fields_pack_length(
+	Alter_inplace_info*	ha_alter_info,
+	const KEY*		new_key,
+	const KEY*		old_key)
+{
+	const KEY_PART_INFO	*old_part, *new_part, *end;
+	const Create_field*	new_field;
+
+	end = old_key->key_part + old_key->user_defined_key_parts;
+	for (old_part = old_key->key_part, new_part = new_key->key_part;
+	     old_part < end; old_part++, new_part++) {
+		new_field = get_field_by_field_no(
+				ha_alter_info->alter_info, new_part->fieldnr);
+
+		if ((ha_alter_info->handler_flags
+		     & Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH)
+		    && old_part->field->type() == MYSQL_TYPE_VARCHAR) {
+
+			if (old_part->field->is_equal((Create_field*) new_field)
+		            != IS_EQUAL_PACK_LENGTH) {
+				return false;
+			}
+		} else if (old_part->length != new_part->length) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/** Check whether the field is a prefix field
+@param[in]	part	part of the key
+@param[in]	table	MySQL table object
+@return true if it is a prefix field */
+static bool innobase_is_prefix_field(const KEY_PART_INFO* part,
+				     const TABLE*	table)
+{
+	Field*	field = part->field;
+
+	if (table != NULL) {
+		field = table->field[field->field_index];
+	}
+
+	return (field->type() == MYSQL_TYPE_VARCHAR
+		&& part->length
+		   < (field->pack_length()
+		      - ((Field_varstring*) field)->length_bytes));
+}
+
+/** Check whether the both keys are equal.
+@param[in]	a		key1
+@param[in]	b		key2
+@param[in]	field_map	mapping between old sql field
+				to new sql field
+@return true if the keys are equal. */
+static bool innobase_equal_keys(
+	const KEY&	a,
+	const KEY&	b,
+	const ulint*	field_map)
+{
+	if (a.user_defined_key_parts != b.user_defined_key_parts) {
+		return false;
+	}
+
+	if ((a.flags & HA_KEYFLAG_MASK) != (b.flags & HA_KEYFLAG_MASK)) {
+		return false;
+	}
+
+	const KEY_PART_INFO	*a_part, *b_part, *end;
+	end = a.key_part + a.user_defined_key_parts;
+	a_part = a.key_part;
+	b_part = b.key_part;
+	while (a_part < end) {
+
+		Field* a_field = a_part->field;
+		Field* b_field = b_part->field;
+
+		if (field_map[a_field->field_index] == ULINT_UNDEFINED
+		    || field_map[a_field->field_index] != b_field->field_index
+		    || a_field->real_type() != b_field->real_type()) {
+			return false;
+		}
+
+		if (innobase_is_prefix_field(a_part, a.table)) {
+			if (!innobase_is_prefix_field(b_part, b.table)
+			    || a_part->length != b_part->length) {
+				return false;
+			}
+		} else if (innobase_is_prefix_field(b_part, b.table)) {
+			return false;
+		}
+
+		a_part++;
+		b_part++;
+	}
+
+	return true;
+}
+
+/** Get the list of keys re-created because of extending varchar columns.
+@param[in]	ha_alter_info	Data used during inplace alter
+@param[out]	ignore_drop_key	list of key numbers to be ignored for drop index
+@param[out]	ignore_add_key list of key numbers to be ignored for add index
+@param[in[	field_map	mapping of old table field to new table field */
+static void innobase_get_change_field_keys(
+	Alter_inplace_info*	ha_alter_info,
+	std::vector<ulint>&	ignore_drop_key,
+	std::vector<ulint>&	ignore_add_key,
+	const ulint*		field_map)
+{
+	for (ulint i = 0; i < ha_alter_info->index_drop_count; i++) {
+		const KEY* drop_key = ha_alter_info->index_drop_buffer[i];
+
+		for (ulint j = 0; j < ha_alter_info->index_add_count; j++) {
+			const KEY* add_key = &ha_alter_info->key_info_buffer[
+					ha_alter_info->index_add_buffer[j]];
+
+			if (!innobase_equal_keys(*add_key, *drop_key, field_map)) {
+				continue;
+			}
+
+			if (strcmp(add_key->name, drop_key->name) != 0
+			    && innobase_check_drop_key_name(
+					ha_alter_info, add_key->name)) {
+				continue;
+			}
+
+			if (innobase_check_key_fields_pack_length(
+				ha_alter_info, add_key, drop_key)) {
+
+				ignore_drop_key.push_back(i);
+				ignore_add_key.push_back(j);
+				break;
+			}
+		}
+	}
+}
+
 /** Get the new non-virtual column names if any columns were renamed
 @param ha_alter_info	Data used during in-place alter
 @param altered_table	MySQL table that is being altered
@@ -4422,7 +4723,8 @@ prepare_inplace_alter_table_dict(
 	ALTER TABLE ADD INDEX so that they are in the correct order
 	in the table. */
 
-	ctx->num_to_add_index = ha_alter_info->index_add_count;
+	ctx->num_to_add_index = ha_alter_info->index_add_count
+					- ctx->num_to_ignore_keys;
 
 	ut_ad(ctx->prebuilt->trx->mysql_thd != NULL);
 	const char*	path = thd_innodb_tmpdir(
@@ -4434,7 +4736,7 @@ prepare_inplace_alter_table_dict(
 		dict_index_is_auto_gen_clust(dict_table_get_first_index(
 						     ctx->new_table)),
 		fts_doc_id_col, add_fts_doc_id, add_fts_doc_id_idx,
-		old_table);
+		old_table, ctx->ignore_add_keys, ctx->num_to_ignore_keys);
 
 	new_clustered = DICT_CLUSTERED & index_defs[0].ind_type;
 
@@ -4447,7 +4749,9 @@ prepare_inplace_alter_table_dict(
 		/* This is not an online operation (LOCK=NONE). */
 	} else if (ctx->add_autoinc == ULINT_UNDEFINED
 		   && num_fts_index == 0
-		   && (!innobase_need_rebuild(ha_alter_info, old_table)
+		   && (!innobase_need_rebuild(
+				ha_alter_info, old_table,
+				ctx->is_ignore_pk_index(ha_alter_info))
 		       || !innobase_fulltext_exist(altered_table))) {
 		/* InnoDB can perform an online operation (LOCK=NONE). */
 	} else {
@@ -4466,7 +4770,9 @@ prepare_inplace_alter_table_dict(
 	is just copied from old table and stored in indexdefs[0] */
 	DBUG_ASSERT(!add_fts_doc_id || new_clustered);
 	DBUG_ASSERT(!!new_clustered ==
-		    (innobase_need_rebuild(ha_alter_info, old_table)
+		    (innobase_need_rebuild(
+			ha_alter_info, old_table,
+			ctx->is_ignore_pk_index(ha_alter_info))
 		     || add_fts_doc_id));
 
 	/* Allocate memory for dictionary index definitions */
@@ -4799,7 +5105,9 @@ prepare_inplace_alter_table_dict(
 			add_cols, ctx->heap);
 		ctx->add_cols = add_cols;
 	} else {
-		DBUG_ASSERT(!innobase_need_rebuild(ha_alter_info, old_table));
+		DBUG_ASSERT(!innobase_need_rebuild(
+				ha_alter_info, old_table,
+				ctx->is_ignore_pk_index(ha_alter_info)));
 		DBUG_ASSERT(old_table->s->primary_key
 			    == altered_table->s->primary_key);
 
@@ -5255,7 +5563,6 @@ innobase_check_foreign_key_index(
 	return(false);
 }
 
-#ifdef MYSQL_RENAME_INDEX
 /**
 Rename a given index in the InnoDB data dictionary.
 
@@ -5322,6 +5629,7 @@ rename_index_in_data_dictionary(
 	DBUG_RETURN(false);
 }
 
+#ifdef MYSQL_RENAME_INDEX
 /**
 Rename all indexes in data dictionary of a given table that are
 specified in ha_alter_info.
@@ -5365,6 +5673,8 @@ rename_indexes_in_data_dictionary(
 	DBUG_RETURN(false);
 }
 
+#endif /* MYSQL_RENAME_INDEX */
+
 /**
 Rename a given index in the InnoDB data dictionary cache.
 
@@ -5409,6 +5719,7 @@ rename_index_in_cache(
 	DBUG_VOID_RETURN;
 }
 
+#ifdef MYSQL_RENAME_INDEX
 /**
 Rename all indexes in data dictionary cache of a given table that are
 specified in ha_alter_info.
@@ -5442,6 +5753,24 @@ rename_indexes_in_cache(
 }
 #endif /* MYSQL_RENAME_INDEX */
 
+/** Rename the index name in cache.
+@param[in]	ctx		alter context
+@param[in]	ha_alter_info	Data used during inplace alter. */
+static void innobase_rename_indexes_in_cache(
+	const ha_innobase_inplace_ctx*	ctx,
+	const Alter_inplace_info*	ha_alter_info)
+{
+	for (ulint i = 0; i < ctx->num_rename_index; i++) {
+		index_name_pair pair = ctx->rename_indexes[i];
+		dict_index_t*	index = dict_table_get_index_on_name(
+				ctx->old_table, pair.old_idx_name);
+		ut_ad(index != NULL);
+		ut_ad(strcmp(index->name, pair.old_idx_name) == 0);
+
+		rename_index_in_cache(index, pair.new_idx_name);
+	}
+}
+
 /** Fill the stored column information in s_cols list.
 @param[in]	altered_table	mysql table object
 @param[in]	table		innodb table object
@@ -5496,6 +5825,104 @@ alter_fill_stored_column(
 	}
 }
 
+/** Get the new field number in the new table for the given field
+@param[in]	alter_info	Data used during inplace alter
+@param[in]	field		field to be searched.
+@return new field no for the given field. */
+static ulint innobase_get_new_field_no(
+	Alter_info*	alter_info,
+	Field*		field)
+{
+	List_iterator_fast<Create_field> cf_it(alter_info->create_list);
+	ulint		field_no = 0;
+
+	while (Create_field* cf = cf_it++) {
+		if (cf->field == field) {
+			return field_no;
+		}
+
+		field_no++;
+	}
+
+	return ULINT_UNDEFINED;
+}
+
+/** Build the field map for the mysql fields
+@param[in]	alter_info	Data used for inplace alter
+@param[in]	table		old table
+@param[in,out]	heap		memory to store field map
+@return field mapping of sql fields */
+static ulint* innobase_build_field_map(
+	Alter_info*	alter_info,
+	const TABLE*	table,
+	mem_heap_t*	heap)
+{
+	ulint* field_map = static_cast<ulint*>(mem_heap_alloc(
+				heap, table->s->fields * sizeof *field_map));
+
+	for (ulint i = 0; i < table->s->fields; i++) {
+		field_map[i] = innobase_get_new_field_no(
+					alter_info, table->field[i]);
+	}
+
+	return field_map;
+}
+
+/** Get the list of index which can be renamed.
+@param[in]	ha_alter_info		Data used for inplace alter operation
+@param[in]	ignore_add_keys		keys to be ignored for add key
+@param[in]	ignore_drop_keys	keys to be ignored for drop key
+@param[in]	heap			memory to store index rename pair
+@param[out]	num_to_rename_index	number of rename indexes exist
+@return list of index name pairs to be renamed. */
+static index_name_pair* innobase_get_rename_index(
+	Alter_inplace_info*	ha_alter_info,
+	const ulint*		ignore_add_keys,
+	const ulint*		ignore_drop_keys,
+	ulint			num_to_ignore_key,
+	mem_heap_t*		heap,
+	ulint&			num_to_rename_index)
+{
+	std::vector<ulint>	rename_indexes;
+
+	for (ulint i = 0; i < num_to_ignore_key; i++) {
+		ulint	drop_key_offset = ignore_drop_keys[i];
+		ulint	add_key_offset = ha_alter_info->index_add_buffer[
+						ignore_add_keys[i]];
+
+		const KEY* drop_key =
+			ha_alter_info->index_drop_buffer[drop_key_offset];
+		const KEY* add_key =
+			&ha_alter_info->key_info_buffer[add_key_offset];
+
+		if (!strcmp(add_key->name, drop_key->name)) {
+			continue;
+		}
+
+		rename_indexes.push_back(i);
+	}
+
+	num_to_rename_index = rename_indexes.size();
+
+	index_name_pair* rename_index_pair = static_cast<index_name_pair*>(
+		mem_heap_alloc(heap,
+			       rename_indexes.size() * sizeof *rename_index_pair));
+
+	for (ulint i = 0; i < rename_indexes.size(); i++) {
+		ulint	drop_key_offset = ignore_drop_keys[rename_indexes.at(i)];
+		ulint	add_key_offset = ha_alter_info->index_add_buffer[
+				ignore_add_keys[rename_indexes.at(i)]];
+
+		char* old_idx_name =
+			ha_alter_info->index_drop_buffer[drop_key_offset]->name;
+		char* new_idx_name =
+			ha_alter_info->key_info_buffer[add_key_offset].name;
+		rename_index_pair[i].old_idx_name = old_idx_name;
+		rename_index_pair[i].new_idx_name = new_idx_name;
+	}
+
+	return rename_index_pair;
+}
 
 /** Allows InnoDB to update internal structures with concurrent
 writes blocked (provided that check_if_supported_inplace_alter()
@@ -5837,6 +6264,61 @@ ha_innobase::prepare_inplace_alter_table(
 		col_names = NULL;
 	}
 
+	ulint* field_map = innobase_build_field_map(
+			ha_alter_info->alter_info, table, heap);
+
+#if 0
+	bool field_change_indexes_exist =
+			((ha_alter_info->handler_flags &
+				Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH)
+			&& (ha_alter_info->handler_flags &
+					(INNOBASE_NON_UNIQ_INDEX_RECREATE
+					 | INNOBASE_UNIQ_INDEX_RECREATE
+					 | INNOBASE_PRIM_INDEX_RECREATE)));
+#endif
+
+	ulint*			ignore_add_keys = NULL;
+	ulint*			ignore_drop_keys = NULL;
+	ulint			num_to_ignore_keys = 0;
+	index_name_pair*	rename_indexes = NULL;
+	ulint			num_to_rename_index = 0;
+	std::vector<ulint>	ignore_drop;
+	std::vector<ulint>	ignore_add;
+
+	innobase_get_change_field_keys(
+			ha_alter_info, ignore_drop, ignore_add, field_map);
+
+	num_to_ignore_keys = ignore_drop.size();
+	ut_ad(ignore_drop.size() == ignore_add.size());
+
+	if (ignore_drop.size() != 0) {
+
+		ignore_drop_keys = static_cast<ulint*>(mem_heap_alloc(
+				heap,
+				ignore_drop.size() * sizeof *ignore_drop_keys));
+
+		ulint i = 0;
+		for (std::vector<ulint>::iterator it = ignore_drop.begin();
+				it != ignore_drop.end(); it++) {
+			ignore_drop_keys[i++] = *it;
+		}
+
+		ignore_add_keys = static_cast<ulint*>(mem_heap_alloc(
+				heap,
+				ignore_add.size() * sizeof *ignore_add_keys));
+
+		i = 0;
+		for (std::vector<ulint>::iterator it = ignore_add.begin();
+				it != ignore_add.end(); it++) {
+			ignore_add_keys[i++] = *it;
+		}
+
+		rename_indexes = innobase_get_rename_index(
+				ha_alter_info, ignore_add_keys,
+				ignore_drop_keys, num_to_ignore_keys,
+				heap, num_to_rename_index);
+	}
+
 	if (ha_alter_info->handler_flags
 	    & Alter_inplace_info::DROP_FOREIGN_KEY) {
 		DBUG_ASSERT(ha_alter_info->alter_info->drop_list.elements > 0);
@@ -5898,32 +6380,42 @@ ha_innobase::prepare_inplace_alter_table(
 			    & (Alter_inplace_info::DROP_INDEX
 			       | Alter_inplace_info::DROP_UNIQUE_INDEX
 			       | Alter_inplace_info::DROP_PK_INDEX));
-		/* Check which indexes to drop. */
-		drop_index = static_cast<dict_index_t**>(
-			mem_heap_alloc(
-				heap, (ha_alter_info->index_drop_count + 1)
-				* sizeof *drop_index));
 
-		for (uint i = 0; i < ha_alter_info->index_drop_count; i++) {
-			const KEY*	key
-				= ha_alter_info->index_drop_buffer[i];
-			dict_index_t*	index
-				= dict_table_get_index_on_name(
-					indexed_table, key->name);
+		if (ha_alter_info->index_drop_count != num_to_ignore_keys) {
+			/* Check which indexes to drop. */
+			drop_index = static_cast<dict_index_t**>(
+				mem_heap_alloc(
+					heap, (ha_alter_info->index_drop_count + 1)
+					* sizeof *drop_index));
 
-			if (!index) {
-				push_warning_printf(
-					m_user_thd,
-					Sql_condition::WARN_LEVEL_WARN,
-					HA_ERR_WRONG_INDEX,
-					"InnoDB could not find key"
-					" with name %s", key->name);
-			} else {
-				ut_ad(!index->to_be_dropped);
-				if (!index->is_primary()) {
-					drop_index[n_drop_index++] = index;
+			for (uint i = 0; i < ha_alter_info->index_drop_count;
+			     i++) {
+
+				if (is_ignore_key(
+					ignore_drop_keys, num_to_ignore_keys, i)) {
+					continue;
+				}
+
+				const KEY*	key
+					= ha_alter_info->index_drop_buffer[i];
+				dict_index_t*	index
+					= dict_table_get_index_on_name(
+						indexed_table, key->name);
+
+				if (!index) {
+					push_warning_printf(
+						m_user_thd,
+						Sql_condition::WARN_LEVEL_WARN,
+						HA_ERR_WRONG_INDEX,
+						"InnoDB could not find key"
+						" with name %s", key->name);
 				} else {
-					drop_primary = index;
+					ut_ad(!index->to_be_dropped);
+					if (!index->is_primary()) {
+						drop_index[n_drop_index++] = index;
+					} else {
+						drop_primary = index;
+					}
 				}
 			}
 		}
@@ -5987,7 +6479,8 @@ ha_innobase::prepare_inplace_alter_table(
 				if (innobase_check_foreign_key_index(
 						ha_alter_info, index,
 						indexed_table, col_names,
-						m_prebuilt->trx, drop_fk, n_drop_fk)) {
+						m_prebuilt->trx, drop_fk,
+						n_drop_fk)) {
 					row_mysql_unlock_data_dictionary(
 						m_prebuilt->trx);
 					m_prebuilt->trx->error_info = index;
@@ -6122,7 +6615,18 @@ ha_innobase::prepare_inplace_alter_table(
 		}
 	}
 
-	if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA)
+	bool	is_alter_data = ha_alter_info->handler_flags & INNOBASE_ALTER_DATA;
+
+	if (ha_alter_info->index_drop_count == num_to_ignore_keys
+	    && ha_alter_info->index_add_count == num_to_ignore_keys) {
+		is_alter_data = ha_alter_info->handler_flags
+			& (INNOBASE_ALTER_DATA
+			   & ~(INNOBASE_NON_UNIQ_INDEX_RECREATE
+			       | INNOBASE_UNIQ_INDEX_RECREATE
+			       | INNOBASE_PRIM_INDEX_RECREATE));
+	}
+
+	if (!is_alter_data
 	    || ((ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)
 		== Alter_inplace_info::CHANGE_CREATE_OPTION
 		&& !innobase_need_rebuild(ha_alter_info, table))) {
@@ -6137,7 +6641,10 @@ ha_innobase::prepare_inplace_alter_table(
 					add_fk, n_add_fk,
 					ha_alter_info->online,
 					heap, indexed_table,
-					col_names, ULINT_UNDEFINED, 0, 0, 0);
+					col_names, ULINT_UNDEFINED, 0, 0, 0,
+					ignore_add_keys, ignore_drop_keys,
+					num_to_ignore_keys, true,
+					rename_indexes, num_to_rename_index);
 		}
 
 		DBUG_ASSERT(m_prebuilt->trx->dict_operation_lock_mode == 0);
@@ -6272,7 +6779,8 @@ ha_innobase::prepare_inplace_alter_table(
 		heap, m_prebuilt->table, col_names,
 		add_autoinc_col_no,
 		ha_alter_info->create_info->auto_increment_value,
-		autoinc_col_max_value, 0);
+		autoinc_col_max_value, 0, ignore_add_keys, ignore_drop_keys,
+		num_to_ignore_keys, false, rename_indexes, num_to_rename_index);
 
 	DBUG_RETURN(prepare_inplace_alter_table_dict(
 			    ha_alter_info, altered_table, table,
@@ -6419,6 +6927,16 @@ ha_innobase::inplace_alter_table(
 		(ha_alter_info->handler_ctx);
 
 	DBUG_ASSERT(ctx);
+
+	if (ctx->ignore_all_keys
+	    && !(ha_alter_info->handler_flags
+			& (INNOBASE_ALTER_DATA
+			   & ~(INNOBASE_NON_UNIQ_INDEX_RECREATE
+			       | INNOBASE_UNIQ_INDEX_RECREATE
+			       | INNOBASE_PRIM_INDEX_RECREATE)))) {
+			DBUG_RETURN(false);
+	}
+
 	DBUG_ASSERT(ctx->trx);
 	DBUG_ASSERT(ctx->prebuilt == m_prebuilt);
 
@@ -7904,6 +8422,34 @@ commit_try_rebuild(
 	}
 }
 
+/** Rename indexes in dictionary.
+@param[in]	ctx		alter info context
+@param[in]	ha_alter_info	Operation used during inplace alter
+@param[out]	trx		transaction to change the index name
+				in dictionary
+@return true if it failed to rename
+@return false if it is success. */
+static bool innobase_rename_index_try(
+	const ha_innobase_inplace_ctx*	ctx,
+	const Alter_inplace_info*	ha_alter_info,
+	trx_t*				trx)
+{
+	for (ulint i = 0; i < ctx->num_rename_index; i++) {
+		index_name_pair pair = ctx->rename_indexes[i];
+		dict_index_t*	index = dict_table_get_index_on_name(
+					ctx->old_table, pair.old_idx_name);
+		ut_ad(index != NULL);
+		ut_ad(strcmp(index->name, pair.old_idx_name) == 0);
+
+		if (rename_index_in_data_dictionary(
+			index, pair.new_idx_name, trx)) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
 /** Apply the changes made during commit_try_rebuild(),
 to the data dictionary cache and the file system.
 @param ctx In-place ALTER TABLE context */
@@ -8106,6 +8652,11 @@ commit_try_norebuild(
 		DBUG_RETURN(true);
 	}
 
+	if (ctx->num_rename_index
+	    && innobase_rename_index_try(ctx, ha_alter_info, trx)) {
+		DBUG_RETURN(true);
+	}
+
 #ifdef MYSQL_RENAME_INDEX
 	if ((ha_alter_info->handler_flags
 	     & Alter_inplace_info::RENAME_INDEX)
@@ -8875,6 +9426,9 @@ ha_innobase::commit_inplace_alter_table(
 				innobase_rename_or_enlarge_columns_cache(
 					ha_alter_info, table,
 					ctx->new_table);
+
+				innobase_rename_indexes_in_cache(
+					ctx, ha_alter_info);
 #ifdef MYSQL_RENAME_INDEX
 				rename_indexes_in_cache(ctx, ha_alter_info);
 #endif
