diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml
index 6613418fd235c6e3697e27a40ff6897af0056542..e9eb1aafbb6f3552a096f3c872bcf0d3f1ad7f3f 100644
--- a/doc/src/sgml/ref/alter_extension.sgml
+++ b/doc/src/sgml/ref/alter_extension.sgml
@@ -25,6 +25,7 @@ PostgreSQL documentation
 <synopsis>
 ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
 ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD <replaceable class="PARAMETER">member_object</replaceable>
+ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP <replaceable class="PARAMETER">member_object</replaceable>
 
 <phrase>where <replaceable class="PARAMETER">member_object</replaceable> is:</phrase>
 
@@ -82,6 +83,17 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><literal>DROP <replaceable class="PARAMETER">member_object</replaceable></literal></term>
+    <listitem>
+     <para>
+      This form removes a member object from the extension.  This is mainly
+      useful in extension upgrade scripts.  The object is not dropped, only
+      disassociated from the extension.
+     </para>
+    </listitem>
+   </varlistentry>
    </variablelist>
 
    See <xref linkend="extend-extensions"> for more information about these
@@ -123,7 +135,8 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD
      <term><replaceable class="parameter">operator_name</replaceable></term>
      <listitem>
       <para>
-       The name of an object to be added to the extension.  Names of tables,
+       The name of an object to be added to or removed from the extension.
+       Names of tables,
        aggregates, domains, foreign tables, functions, operators,
        operator classes, operator families, sequences, text search objects,
        types, and views can be schema-qualified.
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index b2ce148d625ae151ef4fb69863a203bee5ce6dba..2bb7bb3d5fa920b7690959d37126589b0ef9147d 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -199,6 +199,57 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId,
 	return count;
 }
 
+/*
+ * deleteDependencyRecordsForClass -- delete all records with given depender
+ * classId/objectId, dependee classId, and deptype.
+ * Returns the number of records deleted.
+ *
+ * This is a variant of deleteDependencyRecordsFor, useful when revoking
+ * an object property that is expressed by a dependency record (such as
+ * extension membership).
+ */
+long
+deleteDependencyRecordsForClass(Oid classId, Oid objectId,
+								Oid refclassId, char deptype)
+{
+	long		count = 0;
+	Relation	depRel;
+	ScanKeyData key[2];
+	SysScanDesc scan;
+	HeapTuple	tup;
+
+	depRel = heap_open(DependRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_depend_classid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(classId));
+	ScanKeyInit(&key[1],
+				Anum_pg_depend_objid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(objectId));
+
+	scan = systable_beginscan(depRel, DependDependerIndexId, true,
+							  SnapshotNow, 2, key);
+
+	while (HeapTupleIsValid(tup = systable_getnext(scan)))
+	{
+		Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
+
+		if (depform->refclassid == refclassId && depform->deptype == deptype)
+		{
+			simple_heap_delete(depRel, &tup->t_self);
+			count++;
+		}
+	}
+
+	systable_endscan(scan);
+
+	heap_close(depRel, RowExclusiveLock);
+
+	return count;
+}
+
 /*
  * Adjust dependency record(s) to point to a different object of the same type
  *
@@ -470,39 +521,8 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
 void
 markSequenceUnowned(Oid seqId)
 {
-	Relation	depRel;
-	ScanKeyData key[2];
-	SysScanDesc scan;
-	HeapTuple	tup;
-
-	depRel = heap_open(DependRelationId, RowExclusiveLock);
-
-	ScanKeyInit(&key[0],
-				Anum_pg_depend_classid,
-				BTEqualStrategyNumber, F_OIDEQ,
-				ObjectIdGetDatum(RelationRelationId));
-	ScanKeyInit(&key[1],
-				Anum_pg_depend_objid,
-				BTEqualStrategyNumber, F_OIDEQ,
-				ObjectIdGetDatum(seqId));
-
-	scan = systable_beginscan(depRel, DependDependerIndexId, true,
-							  SnapshotNow, 2, key);
-
-	while (HeapTupleIsValid((tup = systable_getnext(scan))))
-	{
-		Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
-
-		if (depform->refclassid == RelationRelationId &&
-			depform->deptype == DEPENDENCY_AUTO)
-		{
-			simple_heap_delete(depRel, &tup->t_self);
-		}
-	}
-
-	systable_endscan(scan);
-
-	heap_close(depRel, RowExclusiveLock);
+	deleteDependencyRecordsForClass(RelationRelationId, seqId,
+									RelationRelationId, DEPENDENCY_AUTO);
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 1da76aca10fac6c47571ee5287d43bd29f4d4892..bc121808bec094299bdd17faf752f6db018bd6b1 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1436,14 +1436,15 @@ AlterExtensionNamespace(List *names, const char *newschema)
 }
 
 /*
- * Execute ALTER EXTENSION ADD
+ * Execute ALTER EXTENSION ADD/DROP
  */
 void
-ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
+ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 {
 	ObjectAddress	extension;
 	ObjectAddress	object;
 	Relation		relation;
+	Oid				oldExtension;
 
 	/*
 	 * For now, insist on superuser privilege.  Later we might want to
@@ -1462,25 +1463,54 @@ ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
 	/*
 	 * Translate the parser representation that identifies the object into
 	 * an ObjectAddress.  get_object_address() will throw an error if the
-	 * object does not exist, and will also acquire a lock on the object
-	 * to guard against concurrent DROP and ALTER EXTENSION ADD operations.
+	 * object does not exist, and will also acquire a lock on the object to
+	 * guard against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
 								&relation, ShareUpdateExclusiveLock);
 
 	/*
-	 * Complain if object is already attached to some extension.
+	 * Check existing extension membership.
 	 */
-	if (getExtensionOfObject(object.classId, object.objectId) != InvalidOid)
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-				 errmsg("%s is already a member of an extension",
-						getObjectDescription(&object))));
+	oldExtension = getExtensionOfObject(object.classId, object.objectId);
 
-	/*
-	 * OK, add the dependency.
-	 */
-	recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
+	if (stmt->action > 0)
+	{
+		/*
+		 * ADD, so complain if object is already attached to some extension.
+		 */
+		if (OidIsValid(oldExtension))
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+					 errmsg("%s is already a member of extension \"%s\"",
+							getObjectDescription(&object),
+							get_extension_name(oldExtension))));
+
+		/*
+		 * OK, add the dependency.
+		 */
+		recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
+	}
+	else
+	{
+		/*
+		 * DROP, so complain if it's not a member.
+		 */
+		if (oldExtension != extension.objectId)
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+					 errmsg("%s is not a member of extension \"%s\"",
+							getObjectDescription(&object),
+							stmt->extname)));
+
+		/*
+		 * OK, drop the dependency.
+		 */
+		if (deleteDependencyRecordsForClass(object.classId, object.objectId,
+											ExtensionRelationId,
+											DEPENDENCY_EXTENSION) != 1)
+			elog(ERROR, "unexpected number of extension dependency records");
+	}
 
 	/*
 	 * If get_object_address() opened the relation for us, we close it to keep
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 83630924f6386ad89021854c96f499d47cb56d59..46acaf8d701abc6be9b8683f30a3f04d066f596c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3251,12 +3251,13 @@ _copyCreateExtensionStmt(CreateExtensionStmt *from)
 	return newnode;
 }
 
-static AlterExtensionAddStmt *
-_copyAlterExtensionAddStmt(AlterExtensionAddStmt *from)
+static AlterExtensionContentsStmt *
+_copyAlterExtensionContentsStmt(AlterExtensionContentsStmt *from)
 {
-	AlterExtensionAddStmt *newnode = makeNode(AlterExtensionAddStmt);
+	AlterExtensionContentsStmt *newnode = makeNode(AlterExtensionContentsStmt);
 
 	COPY_STRING_FIELD(extname);
+	COPY_SCALAR_FIELD(action);
 	COPY_SCALAR_FIELD(objtype);
 	COPY_NODE_FIELD(objname);
 	COPY_NODE_FIELD(objargs);
@@ -4266,8 +4267,8 @@ copyObject(void *from)
 		case T_CreateExtensionStmt:
 			retval = _copyCreateExtensionStmt(from);
 			break;
-		case T_AlterExtensionAddStmt:
-			retval = _copyAlterExtensionAddStmt(from);
+		case T_AlterExtensionContentsStmt:
+			retval = _copyAlterExtensionContentsStmt(from);
 			break;
 		case T_CreateFdwStmt:
 			retval = _copyCreateFdwStmt(from);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 9baa7862e6cca36d4e06fa9268a8de0ec3ef9896..2fbe99937d2e49d901058e43118a978d99201ffc 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1655,9 +1655,10 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
 }
 
 static bool
-_equalAlterExtensionAddStmt(AlterExtensionAddStmt *a, AlterExtensionAddStmt *b)
+_equalAlterExtensionContentsStmt(AlterExtensionContentsStmt *a, AlterExtensionContentsStmt *b)
 {
 	COMPARE_STRING_FIELD(extname);
+	COMPARE_SCALAR_FIELD(action);
 	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_NODE_FIELD(objname);
 	COMPARE_NODE_FIELD(objargs);
@@ -2868,8 +2869,8 @@ equal(void *a, void *b)
 		case T_CreateExtensionStmt:
 			retval = _equalCreateExtensionStmt(a, b);
 			break;
-		case T_AlterExtensionAddStmt:
-			retval = _equalAlterExtensionAddStmt(a, b);
+		case T_AlterExtensionContentsStmt:
+			retval = _equalAlterExtensionContentsStmt(a, b);
 			break;
 		case T_CreateFdwStmt:
 			retval = _equalCreateFdwStmt(a, b);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e2d7d6a02f311e8b9f0eff71431c938166edda45..82ff9accc72761c83afa5b6d7e6fc9cb2e1d8e9a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -185,7 +185,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
 		AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
 		AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
 		AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
-		AlterExtensionAddStmt AlterForeignTableStmt
+		AlterExtensionContentsStmt AlterForeignTableStmt
 		AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
 		AlterRoleStmt AlterRoleSetStmt
 		AlterDefaultPrivilegesStmt DefACLAction
@@ -664,7 +664,7 @@ stmt :
 			| AlterDefaultPrivilegesStmt
 			| AlterDomainStmt
 			| AlterEnumStmt
-			| AlterExtensionAddStmt
+			| AlterExtensionContentsStmt
 			| AlterFdwStmt
 			| AlterForeignServerStmt
 			| AlterForeignTableStmt
@@ -3251,181 +3251,202 @@ create_extension_opt_item:
 
 /*****************************************************************************
  *
- * ALTER EXTENSION name ADD object-identifier
+ * ALTER EXTENSION name ADD/DROP object-identifier
  *
  *****************************************************************************/
 
-AlterExtensionAddStmt:
-			ALTER EXTENSION name ADD_P AGGREGATE func_name aggr_args
+AlterExtensionContentsStmt:
+			ALTER EXTENSION name add_drop AGGREGATE func_name aggr_args
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_AGGREGATE;
 					n->objname = $6;
 					n->objargs = $7;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P CAST '(' Typename AS Typename ')'
+			| ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')'
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_CAST;
 					n->objname = list_make1($7);
 					n->objargs = list_make1($9);
 					$$ = (Node *) n;
 				}
-			| ALTER EXTENSION name ADD_P CONVERSION_P any_name
+			| ALTER EXTENSION name add_drop CONVERSION_P any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_CONVERSION;
 					n->objname = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P DOMAIN_P any_name
+			| ALTER EXTENSION name add_drop DOMAIN_P any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_DOMAIN;
 					n->objname = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P FUNCTION function_with_argtypes
+			| ALTER EXTENSION name add_drop FUNCTION function_with_argtypes
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_FUNCTION;
 					n->objname = $6->funcname;
 					n->objargs = $6->funcargs;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P opt_procedural LANGUAGE name
+			| ALTER EXTENSION name add_drop opt_procedural LANGUAGE name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_LANGUAGE;
 					n->objname = list_make1(makeString($7));
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P OPERATOR any_operator oper_argtypes
+			| ALTER EXTENSION name add_drop OPERATOR any_operator oper_argtypes
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_OPERATOR;
 					n->objname = $6;
 					n->objargs = $7;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P OPERATOR CLASS any_name USING access_method
+			| ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING access_method
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_OPCLASS;
 					n->objname = $7;
 					n->objargs = list_make1(makeString($9));
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P OPERATOR FAMILY any_name USING access_method
+			| ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING access_method
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_OPFAMILY;
 					n->objname = $7;
 					n->objargs = list_make1(makeString($9));
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P SCHEMA name
+			| ALTER EXTENSION name add_drop SCHEMA name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_SCHEMA;
 					n->objname = list_make1(makeString($6));
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P TABLE any_name
+			| ALTER EXTENSION name add_drop TABLE any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_TABLE;
 					n->objname = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P TEXT_P SEARCH PARSER any_name
+			| ALTER EXTENSION name add_drop TEXT_P SEARCH PARSER any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_TSPARSER;
 					n->objname = $8;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P TEXT_P SEARCH DICTIONARY any_name
+			| ALTER EXTENSION name add_drop TEXT_P SEARCH DICTIONARY any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_TSDICTIONARY;
 					n->objname = $8;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P TEXT_P SEARCH TEMPLATE any_name
+			| ALTER EXTENSION name add_drop TEXT_P SEARCH TEMPLATE any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_TSTEMPLATE;
 					n->objname = $8;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P TEXT_P SEARCH CONFIGURATION any_name
+			| ALTER EXTENSION name add_drop TEXT_P SEARCH CONFIGURATION any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_TSCONFIGURATION;
 					n->objname = $8;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P SEQUENCE any_name
+			| ALTER EXTENSION name add_drop SEQUENCE any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_SEQUENCE;
 					n->objname = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P VIEW any_name
+			| ALTER EXTENSION name add_drop VIEW any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_VIEW;
 					n->objname = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P FOREIGN TABLE any_name
+			| ALTER EXTENSION name add_drop FOREIGN TABLE any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_FOREIGN_TABLE;
 					n->objname = $7;
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P FOREIGN DATA_P WRAPPER name
+			| ALTER EXTENSION name add_drop FOREIGN DATA_P WRAPPER name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_FDW;
 					n->objname = list_make1(makeString($8));
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P SERVER name
+			| ALTER EXTENSION name add_drop SERVER name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_FOREIGN_SERVER;
 					n->objname = list_make1(makeString($6));
 					$$ = (Node *)n;
 				}
-			| ALTER EXTENSION name ADD_P TYPE_P any_name
+			| ALTER EXTENSION name add_drop TYPE_P any_name
 				{
-					AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
+					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
 					n->extname = $3;
+					n->action = $4;
 					n->objtype = OBJECT_TYPE;
 					n->objname = $6;
 					$$ = (Node *)n;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 9d1562af7dc6e7b4090097452f84f3cf29c3d773..c942de3bf62cb7b47ab26c1e2b62ff78d808945a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -212,7 +212,7 @@ check_xact_readonly(Node *parsetree)
 		case T_AlterTSDictionaryStmt:
 		case T_AlterTSConfigurationStmt:
 		case T_CreateExtensionStmt:
-		case T_AlterExtensionAddStmt:
+		case T_AlterExtensionContentsStmt:
 		case T_CreateFdwStmt:
 		case T_AlterFdwStmt:
 		case T_DropFdwStmt:
@@ -601,8 +601,8 @@ standard_ProcessUtility(Node *parsetree,
 			CreateExtension((CreateExtensionStmt *) parsetree);
 			break;
 
-		case T_AlterExtensionAddStmt:
-			ExecAlterExtensionAddStmt((AlterExtensionAddStmt *) parsetree);
+		case T_AlterExtensionContentsStmt:
+			ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
 			break;
 
 		case T_CreateFdwStmt:
@@ -1680,7 +1680,7 @@ CreateCommandTag(Node *parsetree)
 			tag = "CREATE EXTENSION";
 			break;
 
-		case T_AlterExtensionAddStmt:
+		case T_AlterExtensionContentsStmt:
 			tag = "ALTER EXTENSION";
 			break;
 
@@ -2307,7 +2307,7 @@ GetCommandLogLevel(Node *parsetree)
 			break;
 
 		case T_CreateExtensionStmt:
-		case T_AlterExtensionAddStmt:
+		case T_AlterExtensionContentsStmt:
 			lev = LOGSTMT_DDL;
 			break;
 
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 1c9623de1e56440540c96f4d3fd2692c805f2abb..c01b02ae3a11fab9f9590ddcef7d36be00df0639 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -855,7 +855,12 @@ psql_completion(char *text, int start, int end)
 	/* ALTER EXTENSION <name> */
 	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
 			 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
-		COMPLETE_WITH_CONST("SET SCHEMA");
+	{
+		static const char *const list_ALTEREXTENSION[] =
+		{"ADD", "DROP", "SET SCHEMA", NULL};
+
+		COMPLETE_WITH_LIST(list_ALTEREXTENSION);
+	}
 
 	/* ALTER FOREIGN */
 	else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 4d7ff8853d1c0c26c61d4aa0eff5bfb204e11869..eda41d69216dcafdc565cd465c20776b5fe6449e 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -205,6 +205,9 @@ extern void recordDependencyOnCurrentExtension(const ObjectAddress *object);
 extern long deleteDependencyRecordsFor(Oid classId, Oid objectId,
 									   bool skipExtensionDeps);
 
+extern long deleteDependencyRecordsForClass(Oid classId, Oid objectId,
+								Oid refclassId, char deptype);
+
 extern long changeDependencyFor(Oid classId, Oid objectId,
 					Oid refClassId, Oid oldRefObjectId,
 					Oid newRefObjectId);
diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h
index 8c07c3aaeffad931421a71e633cf8ec873bfc980..7c94449a6cb0f5e853fe70bd79ae7ce0c87b5069 100644
--- a/src/include/commands/extension.h
+++ b/src/include/commands/extension.h
@@ -37,7 +37,7 @@ extern Oid	InsertExtensionTuple(const char *extName, Oid extOwner,
 					 Datum extConfig, Datum extCondition,
 					 List *requiredExtensions);
 
-extern void ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt);
+extern void ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt);
 
 extern Oid	get_extension_oid(const char *extname, bool missing_ok);
 extern char *get_extension_name(Oid ext_oid);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 1ce97386315119f0260eb1122a524f7bebf6ddda..15bf0631e44c50fb2a94014fd02edf997adcb2b7 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -356,7 +356,7 @@ typedef enum NodeTag
 	T_SecLabelStmt,
 	T_CreateForeignTableStmt,
 	T_CreateExtensionStmt,
-	T_AlterExtensionAddStmt,
+	T_AlterExtensionContentsStmt,
 
 	/*
 	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 2116c94d0d39b3679f6bc97bca3f26d63434c318..b54f0cfe02f7bb5d47d4c37171d12e0543cdbe1e 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1546,14 +1546,15 @@ typedef struct CreateExtensionStmt
 	List	   *options;		/* List of DefElem nodes */
 } CreateExtensionStmt;
 
-typedef struct AlterExtensionAddStmt
+typedef struct AlterExtensionContentsStmt
 {
 	NodeTag		type;
 	char	   *extname;		/* Extension's name */
+	int			action;			/* +1 = add object, -1 = drop object */
 	ObjectType	objtype;		/* Object's type */
 	List	   *objname;		/* Qualified name of the object */
 	List	   *objargs;		/* Arguments if needed (eg, for functions) */
-} AlterExtensionAddStmt;
+} AlterExtensionContentsStmt;
 
 /* ----------------------
  *		Create/Drop FOREIGN DATA WRAPPER Statements