diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 816deda..c00308d 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -888,7 +888,7 @@ psql_completion(const char *text, int start, int end)
 	char	  **matches = NULL;
 
 	/* This array will contain some scannage of the input line. */
-	char	   *previous_words[6];
+	char	   *previous_words[9];
 
 	/* For compactness, we use these macros to reference previous_words[]. */
 #define prev_wd   (previous_words[0])
@@ -897,6 +897,9 @@ psql_completion(const char *text, int start, int end)
 #define prev4_wd  (previous_words[3])
 #define prev5_wd  (previous_words[4])
 #define prev6_wd  (previous_words[5])
+#define prev7_wd  (previous_words[6])
+#define prev8_wd  (previous_words[7])
+#define prev9_wd  (previous_words[8])
 
 	static const char *const sql_commands[] = {
 		"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
@@ -3132,6 +3135,9 @@ psql_completion(const char *text, int start, int end)
 			  pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
 			 pg_strcasecmp(prev_wd, "ON") == 0)
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
+								   " UNION SELECT 'ALL FUNCTIONS IN SCHEMA'"
+								   " UNION SELECT 'ALL SEQUENCES IN SCHEMA'"
+								   " UNION SELECT 'ALL TABLES IN SCHEMA'"
 								   " UNION SELECT 'DATABASE'"
 								   " UNION SELECT 'DOMAIN'"
 								   " UNION SELECT 'FOREIGN DATA WRAPPER'"
@@ -3140,11 +3146,24 @@ psql_completion(const char *text, int start, int end)
 								   " UNION SELECT 'LANGUAGE'"
 								   " UNION SELECT 'LARGE OBJECT'"
 								   " UNION SELECT 'SCHEMA'"
+								   " UNION SELECT 'SEQUENCE'"
+								   " UNION SELECT 'TABLE'"
 								   " UNION SELECT 'TABLESPACE'"
 								   " UNION SELECT 'TYPE'");
 	else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
 			  pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
 			 pg_strcasecmp(prev2_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev_wd, "ALL") == 0)
+	{
+		static const char *const list_privilege_all[] =
+		{"FUNCTIONS IN SCHEMA", "SEQUENCES IN SCHEMA", "TABLES IN SCHEMA", NULL};
+
+		COMPLETE_WITH_LIST(list_privilege_all);
+	}
+
+	else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
+			  pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
+			 pg_strcasecmp(prev2_wd, "ON") == 0 &&
 			 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
 	{
 		static const char *const list_privilege_foreign[] =
@@ -3153,7 +3172,19 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST(list_privilege_foreign);
 	}
 
-	/* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
+	/* Complete "GRANT/REVOKE * ON FOREIGN DATA" with WRAPPER */
+	else if ((pg_strcasecmp(prev5_wd, "GRANT") == 0 || pg_strcasecmp(prev5_wd, "REVOKE") == 0) &&
+			 pg_strcasecmp(prev3_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
+			 pg_strcasecmp(prev_wd, "DATA") == 0)
+		COMPLETE_WITH_CONST("WRAPPER");
+
+	/*
+	 * Complete "GRANT/REMOVE * ON DATABASE/DOMAIN/..." with a list of
+	 * appropriate objects.
+	 *
+	 * Complete "GRANT/REVOKE * ON * " with "TO/FROM".
+	 */
 	else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
 			  pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
 			 pg_strcasecmp(prev2_wd, "ON") == 0)
@@ -3168,6 +3199,10 @@ psql_completion(const char *text, int start, int end)
 			COMPLETE_WITH_QUERY(Query_for_list_of_languages);
 		else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
 			COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
+		else if (pg_strcasecmp(prev_wd, "SEQUENCE") == 0)
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
+		else if (pg_strcasecmp(prev_wd, "TABLE") == 0)
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
 		else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
 			COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
 		else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
@@ -3178,20 +3213,109 @@ psql_completion(const char *text, int start, int end)
 			COMPLETE_WITH_CONST("FROM");
 	}
 
-	/* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
-	else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
+	/*
+	 * Complete "GRANT/REVOKE * ON ALL * IN SCHEMA * TO/FROM" with username,
+	 * GROUP, or PUBLIC.
+	 */
+	else if (((pg_strcasecmp(prev9_wd, "GRANT") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) ||
+			  (pg_strcasecmp(prev9_wd, "REVOKE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0)) &&
+			 pg_strcasecmp(prev7_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev6_wd, "ALL") == 0 &&
+			 pg_strcasecmp(prev4_wd, "IN") == 0 &&
+			 pg_strcasecmp(prev3_wd, "SCHEMA") == 0)
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+
+	/* Complete "GRANT/REVOKE * ON FOREIGN SERVER" with server names.  */
+	else if ((pg_strcasecmp(prev5_wd, "GRANT") == 0 || pg_strcasecmp(prev5_wd, "REVOKE")) &&
+			 pg_strcasecmp(prev3_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
+			 pg_strcasecmp(prev_wd, "SERVER") == 0)
+		COMPLETE_WITH_QUERY(Query_for_list_of_servers);
+
+	/*
+	 * Complete "GRANT/REVOKE * ON FOREIGN DATA WRAPPER * TO/FROM" with username,
+	 * GROUP, or PUBLIC.
+	 */
+	else if (((pg_strcasecmp(prev8_wd, "GRANT") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) ||
+			  (pg_strcasecmp(prev8_wd, "REVOKE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0)) &&
+			 pg_strcasecmp(prev6_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev5_wd, "FOREIGN") == 0 &&
+			 pg_strcasecmp(prev4_wd, "DATA") == 0 &&
+			 pg_strcasecmp(prev3_wd, "WRAPPER") == 0)
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+
+	/*
+	 * Complete "GRANT/REVOKE * ON FOREIGN SERVER * TO/FROM" with username,
+	 * GROUP, or PUBLIC.
+	 */
+	else if (((pg_strcasecmp(prev7_wd, "GRANT") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) ||
+			  (pg_strcasecmp(prev7_wd, "REVOKE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0)) &&
+			 pg_strcasecmp(prev5_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
+			 pg_strcasecmp(prev3_wd, "SERVER") == 0)
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+
+	/*
+	 * Complete "GRANT/REVOKE * ON * * TO/FROM" with username, GROUP, or
+	 * PUBLIC.
+	 */
+	else if (((pg_strcasecmp(prev6_wd, "GRANT") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) ||
+			  (pg_strcasecmp(prev6_wd, "REVOKE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0)) &&
+			 pg_strcasecmp(prev4_wd, "ON") == 0)
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+
+	/*
+	 * Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC.
+	 */
+	else if (((pg_strcasecmp(prev5_wd, "GRANT") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) ||
+			  (pg_strcasecmp(prev5_wd, "REVOKE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0)) &&
+			 pg_strcasecmp(prev3_wd, "ON") == 0)
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+
+	/* Complete "GRANT/REVOKE * ON * *" with TO or FROM */
+	else if ((pg_strcasecmp(prev5_wd, "GRANT") == 0 || pg_strcasecmp(prev5_wd, "REVOKE") == 0) &&
 			 pg_strcasecmp(prev3_wd, "ON") == 0)
 	{
-		if (pg_strcasecmp(prev_wd, "TO") == 0)
-			COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+		if (pg_strcasecmp(prev5_wd, "GRANT") == 0)
+			COMPLETE_WITH_CONST("TO");
 		else
+			COMPLETE_WITH_CONST("FROM");
+	}
+
+	/* Complete "GRANT/REVOKE * ON ALL * IN SCHEMA *" with TO or FROM */
+	else if ((pg_strcasecmp(prev8_wd, "GRANT") == 0 || pg_strcasecmp(prev8_wd, "REVOKE") == 0) &&
+			 pg_strcasecmp(prev6_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev5_wd, "ALL") == 0 &&
+			 pg_strcasecmp(prev3_wd, "IN") == 0 &&
+			 pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
+	{
+		if (pg_strcasecmp(prev8_wd, "GRANT") == 0)
 			COMPLETE_WITH_CONST("TO");
+		else
+			COMPLETE_WITH_CONST("FROM");
 	}
-	else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
-			 pg_strcasecmp(prev3_wd, "ON") == 0)
+
+	/* Complete "GRANT/REVOKE * ON FOREIGN DATA WRAPPER *" with TO or FROM */
+	else if ((pg_strcasecmp(prev7_wd, "GRANT") == 0 || pg_strcasecmp(prev7_wd, "REVOKE") == 0) &&
+			 pg_strcasecmp(prev5_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
+			 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
+			 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
 	{
-		if (pg_strcasecmp(prev_wd, "FROM") == 0)
-			COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+		if (pg_strcasecmp(prev7_wd, "GRANT") == 0)
+			COMPLETE_WITH_CONST("TO");
+		else
+			COMPLETE_WITH_CONST("FROM");
+	}
+
+	/* Complete "GRANT/REVOKE * ON FOREIGN SERVER *" with TO or FROM */
+	else if ((pg_strcasecmp(prev6_wd, "GRANT") == 0 || pg_strcasecmp(prev6_wd, "REVOKE") == 0) &&
+			 pg_strcasecmp(prev4_wd, "ON") == 0 &&
+			 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
+			 pg_strcasecmp(prev2_wd, "SERVER") == 0)
+	{
+		if (pg_strcasecmp(prev6_wd, "GRANT") == 0)
+			COMPLETE_WITH_CONST("TO");
 		else
 			COMPLETE_WITH_CONST("FROM");
 	}
