diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 1017f2eed1..c5b8562cb5 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -31,6 +31,7 @@
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "parser/parse_oper.h"
+#include "parser/scansup.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
@@ -79,6 +80,10 @@ validOperatorName(const char *name)
 	if (len == 0 || len >= NAMEDATALEN)
 		return false;
 
+	/* Is this a Named Operator? */
+	if (validNamedOperator(name))
+		return true;
+
 	/* Can't contain any invalid characters */
 	/* Test string here should match op_chars in scan.l */
 	if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index db8b0fe8eb..cef1da0305 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -379,6 +379,15 @@ self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=]
 op_chars		[\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
 operator		{op_chars}+
 
+/*
+ * Named Operators, e.g. :foo:
+ *
+ * {namedopfailed} is an error rule to avoid scanner backup when {namedop}
+ * fails to match its trailing ":".
+ */
+namedop			\:{identifier}\:
+namedopfailed	\:{identifier}
+
 /*
  * Numbers
  *
@@ -768,6 +777,23 @@ other			.
 				}
 <xdolq><<EOF>>	{ yyerror("unterminated dollar-quoted string"); }
 
+{namedop}		{
+					SET_YYLLOC();
+					if (yyleng >= NAMEDATALEN)
+						yyerror("operator name too long");
+					/* XXX Should we support double-quoted, case sensitive names? */
+					yylval->str = downcase_identifier(yytext, yyleng, false, false);
+					return Op;
+				}
+
+{namedopfailed}	{
+					SET_YYLLOC();
+					/* throw back all but the initial ':' */
+					yyless(1);
+					/* and treat it as {self}, since ':' is a member of that set of chars. */
+					return yytext[0];
+				}
+
 {xdstart}		{
 					SET_YYLLOC();
 					BEGIN(xd);
diff --git a/src/backend/parser/scansup.c b/src/backend/parser/scansup.c
index 602108a40f..678d9d0e5c 100644
--- a/src/backend/parser/scansup.c
+++ b/src/backend/parser/scansup.c
@@ -125,3 +125,71 @@ scanner_isspace(char ch)
 		return true;
 	return false;
 }
+
+bool
+validNamedOperator(const char *name)
+{
+	size_t	len = strlen(name);
+	bool	valid_identifier;
+	char   *tmp;
+
+	if (len < 3 || len >= NAMEDATALEN)
+	   return false;
+
+	if (name[0] != ':' || name[len-1] != ':')
+		return false;
+
+	tmp = pstrdup(name);
+
+	// Disregard the delimiters
+	tmp[len-1] = '\0';
+	tmp += 1;
+	valid_identifier = validIdentifier(tmp);
+	tmp -= 1;
+	pfree(tmp);
+
+	return valid_identifier;
+}
+
+/*
+ * Function to resemble the same check as the following lex
+ * rules in scan.l:
+ *
+ * ident_start		[A-Za-z\200-\377_]
+ * ident_cont		[A-Za-z\200-\377_0-9\$]
+ *
+ * Note: this function does not check if the identifier length
+ * is less than NAMEDATALEN.
+ */
+bool
+validIdentifier(const char *name)
+{
+	uint8	c;
+	size_t	i, len = strlen(name);
+
+	// Reject if first character is not part of ident_start
+	c = name[0];
+	if ( !(c == '_'
+		|| (c >='A' && c <= 'Z')
+		|| (c >='a' && c <= 'z')
+		|| (c >= 0200 && c <= 0377)))
+	{
+		return false;
+	}
+
+	// Reject if other characters are not part of ident_cont
+	for (i = 1; i < len; ++i)
+	{
+		c = name[i];
+		if ( !(c == '_' || c == '$'
+			|| (c >='A' && c <= 'Z')
+			|| (c >='a' && c <= 'z')
+			|| (c >='0' && c <= '9')
+			|| (c >= 0200 && c <= 0377)))
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index da427f4d4a..0aafb3297e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -62,6 +62,7 @@
 #include "getopt_long.h"
 #include "libpq/libpq-fs.h"
 #include "parallel.h"
+#include "common/scansup.h"
 #include "pg_backup_db.h"
 #include "pg_backup_utils.h"
 #include "pg_dump.h"
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index ae531ec240..39bacc6738 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -317,6 +317,15 @@ self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=]
 op_chars		[\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
 operator		{op_chars}+
 
+/*
+ * Named Operators, e.g. :foo:
+ *
+ * {namedopfailed} is an error rule to avoid scanner backup when {namedop}
+ * fails to match its trailing ":".
+ */
+namedop			\:{identifier}\:
+namedopfailed	\:{identifier}
+
 /*
  * Numbers
  *
@@ -570,6 +579,16 @@ other			.
 					ECHO;
 				}
 
+{namedop}		{
+					ECHO;
+				}
+
+{namedopfailed}	{
+					/* throw back all but the initial ':' */
+					yyless(1);
+					ECHO;
+				}
+
 {xdstart}		{
 					BEGIN(xd);
 					ECHO;
diff --git a/src/include/parser/scansup.h b/src/include/parser/scansup.h
index ff65224bf6..0f6aff8b44 100644
--- a/src/include/parser/scansup.h
+++ b/src/include/parser/scansup.h
@@ -24,4 +24,7 @@ extern void truncate_identifier(char *ident, int len, bool warn);
 
 extern bool scanner_isspace(char ch);
 
+extern bool validNamedOperator(const char *name);
+extern bool validIdentifier(const char *name);
+
 #endif							/* SCANSUP_H */
