Index: wp-admin/includes/upgrade.php
===================================================================
--- wp-admin/includes/upgrade.php	(revision 40271)
+++ wp-admin/includes/upgrade.php	(working copy)
@@ -2228,6 +2228,9 @@
 		// Separate field lines into an array.
 		$flds = explode("\n", $qryline);
 
+		// An array to hold the index parts, for later comparison to existing indexes. 
+		$new_indices_ary = array();
+
 		// For every field line specified in the query.
 		foreach ( $flds as $fld ) {
 			$fld = trim( $fld, " \t\n\r\0\x0B," ); // Default trim characters, plus ','.
@@ -2291,6 +2294,9 @@
 					// Escape the index name with backticks. An index for a primary key has no name.
 					$index_name = ( 'PRIMARY KEY' === $index_type ) ? '' : '`' . strtolower( $index_matches['index_name'] ) . '`';
 
+					// Save the index name for use in the $new_indices_ary array.
+					$new_indices_ary_key = empty( $index_name ) ? 'primary' : strtolower( $index_matches['index_name'] );
+
 					// Parse the columns. Multiple columns are separated by a comma.
 					$index_columns = $index_columns_without_subparts = array_map( 'trim', explode( ',', $index_matches['index_columns'] ) );
 
@@ -2329,12 +2335,28 @@
 						if ( isset( $index_column_matches['sub_part'] ) ) {
 							$index_column .= '(' . $index_column_matches['sub_part'] . ')';
 						}
+
+						$new_indices_ary[$new_indices_ary_key]['columns'][] = array('fieldname' => $index_column_matches['column_name'], 'subpart' => ( empty( $index_column_matches['sub_part']) ? null : $index_column_matches['sub_part'] ));
 					}
 
 					// Build the normalized index definition and add it to the list of indices.
 					$indices[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns ) . ")";
 					$indices_without_subparts[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns_without_subparts ) . ")";
 
+					// Set the unique and index_type values.
+					$new_indices_ary[$new_indices_ary_key]['unique'] = (false !== strpos($index_type,'PRIMARY') || false !== strpos($index_type,'UNIQUE') ) ? true : false;
+
+					// SHOW INDEX FROM returns BTREE, FULLTEXT, HASH or RTREE. SPATIAL and FULLTEXT should be specified, and MySQL uses BTREE unless HASH is specified explicitly. 
+					if ( 'FULLTEXT KEY' === $index_type ) {
+						$new_indices_ary[$new_indices_ary_key]['index_type'] = 'FULLTEXT';
+					} else if ( 'SPATIAL' === $index_type ) {
+						$new_indices_ary[$new_indices_ary_key]['index_type'] = 'RTREE';
+					} else if ( false !== stripos( $fld, 'USING HASH' ) ) {
+						$new_indices_ary[$new_indices_ary_key]['index_type'] = 'HASH';
+					} else {
+						$new_indices_ary[$new_indices_ary_key]['index_type'] = 'BTREE';
+					}
+
 					// Destroy no longer needed variables.
 					unset( $index_column, $index_column_matches, $index_matches, $index_type, $index_name, $index_columns, $index_columns_without_subparts );
 
@@ -2360,8 +2382,21 @@
 				$fieldtype = $matches[1];
 				$fieldtype_lowercased = strtolower( $fieldtype );
 
+				/**
+				 * If the new AUTO_INCREMENT settings don't match the existing ones, change the column.
+				 *
+				 * Note: We need to do this first, because adding AI to an existing column will break things
+				 */
+				$old_has_ai = 'auto_increment' === $tablefield->Extra;
+				$new_has_ai = !(false === strpos( strtolower( $cfields[ $tablefield_field_lowercased ] ), 'auto_increment' ));
+				if ( $old_has_ai !== $new_has_ai  ) {
+					$iqueries[] = "ALTER TABLE {$table} CHANGE COLUMN `{$tablefield->Field}` " . $cfields[ $tablefield_field_lowercased ];
+					$use_or_not = 'auto_increment' === $tablefield->Extra  ? 'not use' : 'use';
+					$for_update[] = "Set column {$tablefield->Field} to {$use_or_not} AUTO_INCREMENT";
+				}  
+				
 				// Is actual field type different from the field type in query?
-				if ($tablefield->Type != $fieldtype) {
+				else if ($tablefield->Type != $fieldtype) {
 					$do_change = true;
 					if ( in_array( $fieldtype_lowercased, $text_fields ) && in_array( $tablefield_type_lowercased, $text_fields ) ) {
 						if ( array_search( $fieldtype_lowercased, $text_fields ) < array_search( $tablefield_type_lowercased, $text_fields ) ) {
@@ -2376,6 +2411,19 @@
 					}
 
 					if ( $do_change ) {
+						/**
+						 * If we're changing an AI column, we're going to drop and re-add the AI designation
+						 * so that if we're also modifying an index, we won't trip up that process.
+						 */
+						if ( $new_has_ai ) { 
+							// Remove the AI designation for now.
+							$cfields[ $tablefield_field_lowercased ] = str_ireplace( 'auto_increment', '', $cfields[ $tablefield_field_lowercased ] );
+
+							// Then re-add it afterwards.
+							$iqueries[] = "ALTER TABLE {$table} MODIFY COLUMN {$cfields[ $tablefield_field_lowercased ]} AUTO_INCREMENT";
+							$for_update[] = "Set column {$tablefield->Field} to use AUTO_INCREMENT";
+						}
+
 						// Add a query to change the column type.
 						$cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN `{$tablefield->Field}` " . $cfields[ $tablefield_field_lowercased ];
 						$for_update[$table.'.'.$tablefield->Field] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}";
@@ -2401,6 +2449,25 @@
 
 		// For every remaining field specified for the table.
 		foreach ($cfields as $fieldname => $fielddef) {
+			/**
+			 * A statement tries to add an AUTO_INCREMENT column to an existing table
+			 * will trigger an error because an AUTO_INCREMENT column must be indexed.
+			 *
+			 * We're going to split out the AUTO_INCREMENT piece to handle after we've
+			 * added the index.
+			 */
+			if ( false !== strpos( strtolower( $fielddef ), 'auto_increment' ) ) {
+				$fielddef = str_ireplace( 'auto_increment', '', $fielddef );
+
+				/**
+				 * We want to add the AUTO_INCREMENT properties to the column after all other columns, 
+				 * have 
+				 * so we add it to $iqueries which run after $cqueries.
+				 */ 
+				$iqueries[] = "ALTER TABLE {$table} MODIFY COLUMN {$fielddef} AUTO_INCREMENT";
+				$for_update[] = "Set column {$fieldname} to use AUTO_INCREMENT";
+			}
+
 			// Push a query line into $cqueries that adds the field to that table.
 			$cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef";
 			$for_update[$table.'.'.$fieldname] = 'Added column '.$table.'.'.$fieldname;
@@ -2426,6 +2493,58 @@
 			// For each actual index in the index array.
 			foreach ($index_ary as $index_name => $index_data) {
 
+				// Since we don't drop existing indexes unless we have to, we don't need to do this unless we are significantly changing an index.
+				if ( isset( $new_indices_ary[ $index_name ] ) ) {
+					$drop_this_index = false;
+					if ( $index_data['unique'] !== $new_indices_ary[$index_name]['unique'] ) { // An index which wasn't unique but now is, or vice-versa.
+						$drop_this_index = true;
+					} else if ( null !== $new_indices_ary[$index_name]['index_type'] && $new_indices_ary[$index_name]['index_type'] !== $index_data['index_type'] ) { // If the user has specified an index method ( FULLTEXT, HASH or BTREE).
+						$drop_this_index = true;
+					} else if ( count( $new_indices_ary[$index_name]['columns'] ) !== count( $index_data['columns'] ) ) { // If there are a different number of columns in the index.
+						$drop_this_index = true;
+					} else {
+						foreach( $new_indices_ary[$index_name]['columns'] as $column_idx => $new_column ) {
+							if ( !array_key_exists($column_idx,$index_data['columns']) || $index_data['columns'][$column_idx]['fieldname'] !== $new_column['fieldname'] ) { // If the columns are in a different order.
+								$drop_this_index = true;
+								break;
+							}
+						}
+					}
+
+					if ( $drop_this_index ) {
+						if ( 'primary' === $index_name ){
+
+							// If the column is an AUTO_INCREMENT column, we need to drop the AUTO_INCREMENT designation before dropping the index.
+							foreach( $tablefields as $tablefield ) {
+								if ( 'auto_increment' === $tablefield->Extra && 'PRI' === $tablefield->Key ) {
+
+									$column_already_altered = false;
+									foreach( $cqueries as $k => $maybe_alter ) {
+										// However, if we are already altering the column, we won't touch it here, since we would undo any type or sub-type changes.
+										if ( false !== strpos( $maybe_alter, 'ALTER TABLE' ) &&  ( false !== strpos( $maybe_alter, '`' . $tablefield->Field . '`' ) || false !== strpos( $maybe_alter, ' ' . $tablefield->Field . ' ' ) ) ) {
+											$column_already_altered = true;
+										}
+									}
+
+									if ( !$column_already_altered ) {
+										$cqueries[] = "ALTER TABLE {$table} MODIFY {$tablefield->Field} {$tablefield->Type} NOT NULL;";
+										$for_update[] = 'Removed auto_increment from ' . $tablefield->Field . ' in order to remove primary key';
+									}
+								}
+							}
+
+							$cqueries[] = "ALTER TABLE {$table} DROP PRIMARY KEY";
+							$for_update[] = "Dropped old primary key from {$table}";
+						} else {
+							$cqueries[] = "DROP INDEX {$index_name} ON {$table}";
+							$for_update[] = 'Removed index ' . $index_name . ' from ' . $table;
+						}
+
+						unset( $index_ary[$index_name] );
+						continue;
+					}
+				}
+
 				// Build a create string to compare to the query.
 				$index_string = '';
 				if ($index_name == 'primary') {
