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..8587b82c8d 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -379,6 +379,16 @@ self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=]
 op_chars		[\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
 operator		{op_chars}+
 
+/*
+ * Named Operators, e.g. \{foo}
+ *
+ * {namedopfailed*} are error rules to avoid scanner backup when
+ * {namedop} fails to match its trailing tokens.
+ */
+namedop			\\\{{identifier}\}
+namedopfailed1	\\\{{identifier}
+namedopfailed2	\\\{
+
 /*
  * Numbers
  *
@@ -768,6 +778,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;
+				}
+
+{namedopfailed1}	{
+					yyerror("unexpected token");
+				}
+
+{namedopfailed2}	{
+					yyerror("unexpected token");
+				}
+
 {xdstart}		{
 					SET_YYLLOC();
 					BEGIN(xd);
diff --git a/src/backend/parser/scansup.c b/src/backend/parser/scansup.c
index 602108a40f..f209ac3752 100644
--- a/src/backend/parser/scansup.c
+++ b/src/backend/parser/scansup.c
@@ -125,3 +125,65 @@ scanner_isspace(char ch)
 		return true;
 	return false;
 }
+
+/*
+ * validNamedOperator() -- return true if name adheres to the scanner rule
+ * {namedop}
+ */
+bool
+validNamedOperator(const char *name)
+{
+	size_t	len = strlen(name);
+	bool	valid_identifier;
+
+	if (len < 4 || len >= NAMEDATALEN)
+	   return false;
+
+	if (name[0] != '\\' || name[1] != '{' || name[len-1] != '}')
+		return false;
+
+	// Disregard the delimiters
+	valid_identifier = validIdentifier(name + 2, len - 3);
+
+	return valid_identifier;
+}
+
+/*
+ * validIdentifier() -- return true if name adheres to the scanner rule
+ * {identifier}
+ *
+ * Note: this function does not check if the identifier length
+ * is less than NAMEDATALEN.
+ */
+bool
+validIdentifier(const char *name, size_t len)
+{
+	uint8	c;
+	size_t	i;
+
+	// 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/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index ae531ec240..98a2561886 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -317,6 +317,16 @@ self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=]
 op_chars		[\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
 operator		{op_chars}+
 
+/*
+ * Named Operators, e.g. :foo:
+ *
+ * {namedopfailed*} are error rules to avoid scanner backup when
+ * {namedop} fails to match its trailing tokens.
+ */
+namedop			\\\{{identifier}\}
+namedopfailed1	\\\{{identifier}
+namedopfailed2	\\\{
+
 /*
  * Numbers
  *
@@ -570,6 +580,18 @@ other			.
 					ECHO;
 				}
 
+{namedop}		{
+					ECHO;
+				}
+
+{namedopfailed1}	{
+					ECHO;
+				}
+
+{namedopfailed2}	{
+					ECHO;
+				}
+
 {xdstart}		{
 					BEGIN(xd);
 					ECHO;
diff --git a/src/include/parser/scansup.h b/src/include/parser/scansup.h
index ff65224bf6..b9eb0a96a4 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, size_t len);
+
 #endif							/* SCANSUP_H */
diff --git a/test.sql b/test.sql
new file mode 100644
index 0000000000..4d0c44c629
--- /dev/null
+++ b/test.sql
@@ -0,0 +1,38 @@
+
+create operator \{hello_named_operators} (function = box_add, leftarg = box, rightarg = point);
+
+select '((0,0), (1,1))'::box \{hello_named_operators} '(1,1)'::point;
+
+drop operator \{hello_named_operators}(box, point);
+
+create operator \{add_point} (function = box_add, leftarg = box, rightarg = point);
+
+create table test(a box);
+
+insert into test values('((0,0),(1,1))'), ('((0,0),(2,1))');
+
+select a as original, a \{add_point} '(1,1)' as modified from test;
+
+CREATE OPERATOR \{equal_1} (
+    LEFTARG = int,
+    RIGHTARG = int,
+    PROCEDURE = int4eq,
+    COMMUTATOR = \{equal_1}
+);
+
+CREATE OPERATOR \{equal_2} (
+    LEFTARG = int,
+    RIGHTARG = int,
+    PROCEDURE = int4eq,
+    COMMUTATOR = equal_2 -- The absence of delimiters causes an expected failure
+);
+
+
+\! pg_dump -U postgres --schema public
+
+drop operator \{add_point}(box, point);
+drop operator \{equal_1}(int, int);
+drop operator \{equal_2}(int, int);
+
+drop table test;
+
