diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index d5e47b56e75f7094df39460851d5f36a5894166f..491246fea69810ffbe2fb9772d353d9e4fa97180 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2656,6 +2656,22 @@ bar
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>COMP_KEYWORD_CASE</varname></term>
+        <listitem>
+        <para>
+        Determines which letter case to use when completing an SQL key word.
+        If set to <literal>lower</literal> or <literal>upper</literal>, the
+        completed word will be in lower or upper case, respectively.  If set
+        to <literal>preserve-lower</literal>
+        or <literal>preserve-upper</literal> (the default), the completed word
+        will be in the case of the word already entered, but words being
+        completed without anything entered will be in lower or upper case,
+        respectively.
+        </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>DBNAME</varname></term>
         <listitem>
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 23b7a907f7ee90d929051ce34913666f99810d42..a50e7356f1d25a8872584c6c437aae60ff9f87e2 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -697,7 +697,7 @@ static char **complete_from_variables(char *text,
 						const char *prefix, const char *suffix);
 static char *complete_from_files(const char *text, int state);
 
-static char *pg_strdup_same_case(const char *s, const char *ref);
+static char *pg_strdup_keyword_case(const char *s, const char *ref);
 static PGresult *exec_query(const char *query);
 
 static void get_previous_words(int point, char **previous_words, int nwords);
@@ -3125,7 +3125,7 @@ create_or_drop_command_generator(const char *text, int state, bits32 excluded)
 	{
 		if ((pg_strncasecmp(name, text, string_length) == 0) &&
 			!(words_after_create[list_index - 1].flags & excluded))
-			return pg_strdup_same_case(name, text);
+			return pg_strdup_keyword_case(name, text);
 	}
 	/* if nothing matches, return NULL */
 	return NULL;
@@ -3412,9 +3412,9 @@ complete_from_list(const char *text, int state)
 			if (completion_case_sensitive)
 				return pg_strdup(item);
 			else
-				/* If case insensitive matching was requested initially, return
-				 * it in the case of what was already entered. */
-				return pg_strdup_same_case(item, text);
+				/* If case insensitive matching was requested initially, adjust
+				 * the case according to setting. */
+				return pg_strdup_keyword_case(item, text);
 		}
 	}
 
@@ -3451,9 +3451,9 @@ complete_from_const(const char *text, int state)
 		if (completion_case_sensitive)
 			return pg_strdup(completion_charp);
 		else
-			/* If case insensitive matching was requested initially, return it
-			 * in the case of what was already entered. */
-			return pg_strdup_same_case(completion_charp, text);
+			/* If case insensitive matching was requested initially, adjust the
+			 * case according to setting. */
+			return pg_strdup_keyword_case(completion_charp, text);
 	}
 	else
 		return NULL;
@@ -3561,27 +3561,48 @@ complete_from_files(const char *text, int state)
 
 
 /*
- * Make a pg_strdup copy of s and convert it to the same case as ref.
+ * Make a pg_strdup copy of s and convert the case according to
+ * COMP_KEYWORD_CASE variable, using ref as the text that was already entered.
  */
 static char *
-pg_strdup_same_case(const char *s, const char *ref)
+pg_strdup_keyword_case(const char *s, const char *ref)
 {
 	char *ret, *p;
 	unsigned char first = ref[0];
+	int		tocase;
+	const char *varval;
+
+	varval = GetVariable(pset.vars, "COMP_KEYWORD_CASE");
+	if (!varval)
+		tocase = 0;
+	else if (strcmp(varval, "lower") == 0)
+		tocase = -2;
+	else if (strcmp(varval, "preserve-lower") == 0)
+		tocase = -1;
+	else if (strcmp(varval, "preserve-upper") == 0)
+		tocase = +1;
+	else if (strcmp(varval, "upper") == 0)
+		tocase = +2;
+	else
+		tocase = 0;
 
-	if (isalpha(first))
-	{
-		ret = pg_strdup(s);
-		if (islower(first))
-			for (p = ret; *p; p++)
-				*p = pg_tolower((unsigned char) *p);
-		else
-			for (p = ret; *p; p++)
-				*p = pg_toupper((unsigned char) *p);
-		return ret;
-	}
+	/* default */
+	if (tocase == 0)
+		tocase = +1;
+
+	ret = pg_strdup(s);
+
+	if (tocase == -2
+		|| ((tocase == -1 || tocase == +1) && islower(first))
+		|| (tocase == -1 && !isalpha(first))
+		)
+		for (p = ret; *p; p++)
+			*p = pg_tolower((unsigned char) *p);
 	else
-		return pg_strdup(s);
+		for (p = ret; *p; p++)
+			*p = pg_toupper((unsigned char) *p);
+
+	return ret;
 }