diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml
index b946eab..e852f1d 100644
--- a/doc/src/sgml/ref/lock.sgml
+++ b/doc/src/sgml/ref/lock.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-LOCK [ TABLE ] [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ] [, ...] [ IN <replaceable class="PARAMETER">lockmode</replaceable> MODE ] [ NOWAIT ]
+LOCK [ TABLE ] [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ] [, ...] [ IN <replaceable class="PARAMETER">lockmode</replaceable> MODE ] [ NOWAIT | DEFERRABLE ]
 
 <phrase>where <replaceable class="PARAMETER">lockmode</replaceable> is one of:</phrase>
 
@@ -39,7 +39,23 @@ LOCK [ TABLE ] [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ]
    <literal>NOWAIT</literal> is specified, <command>LOCK
    TABLE</command> does not wait to acquire the desired lock: if it
    cannot be acquired immediately, the command is aborted and an
-   error is emitted.  Once obtained, the lock is held for the
+   error is emitted.  
+  </para>
+
+  <para>
+   If <literal>DEFERRABLE</literal> is specified,
+   <command>LOCK TABLE</command> will wait without blocking for the
+   duration of <xref linkend="guc-max-lock-deferrable-wait-time">
+   for all locks to become available. If all locks cannot be obtained
+   simultaneously before the timeout then none of the structures 
+   will be locked and an error is emitted. Since it is non-blocking,
+   other transactions may obtain locks freely and may cause the
+   required wait time to be infinite. Use <varname>statement_timeout</varname>
+   for to restrict the wait time.
+  </para>
+
+  <para>
+   Once obtained, the lock is held for the
    remainder of the current transaction.  (There is no <command>UNLOCK
    TABLE</command> command; locks are always released at transaction
    end.)
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 34ba385..4259072 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -4865,6 +4865,9 @@ l3:
 										RelationGetRelationName(relation))));
 
 						break;
+					case LockWaitNonBlock:
+						elog(ERROR, "unsupported lock wait_policy LockWaitNonBlock");
+						break;
 				}
 
 				/*
@@ -4902,6 +4905,9 @@ l3:
 									 errmsg("could not obtain lock on row in relation \"%s\"",
 										RelationGetRelationName(relation))));
 						break;
+					case LockWaitNonBlock:
+						elog(ERROR, "unsupported lock wait_policy LockWaitNonBlock");
+						break;
 				}
 			}
 
@@ -5125,6 +5131,9 @@ heap_acquire_tuplock(Relation relation, ItemPointer tid, LockTupleMode mode,
 					errmsg("could not obtain lock on row in relation \"%s\"",
 						   RelationGetRelationName(relation))));
 			break;
+		case LockWaitNonBlock:
+			elog(ERROR, "unsupported lock wait_policy LockWaitNonBlock");
+			break;
 	}
 	*have_tuple_lock = true;
 
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 446b2ac..a0c4e56 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -46,6 +46,7 @@
 #include "nodes/makefuncs.h"
 #include "parser/parse_func.h"
 #include "storage/ipc.h"
+#include "storage/lock.h"
 #include "storage/lmgr.h"
 #include "storage/sinval.h"
 #include "utils/acl.h"
@@ -223,14 +224,19 @@ Datum		pg_is_other_temp_schema(PG_FUNCTION_ARGS);
  * If the schema or relation is not found, return InvalidOid if missing_ok
  * = true, otherwise raise an error.
  *
- * If nowait = true, throw an error if we'd have to wait for a lock.
+ * If waitpolicy = LockWaitBlock, throw an error if we'd have to wait
+ * for a lock.
+ *
+ * If waitpolicy = LockWaitNonBlock, return InvalidOid if a lock cannot
+ * be obtained. Callers should not specify both LockWaitNonBlock and
+ * missing_ok.
  *
  * Callback allows caller to check permissions or acquire additional locks
  * prior to grabbing the relation lock.
  */
 Oid
 RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
-						 bool missing_ok, bool nowait,
+						 bool missing_ok, LockWaitPolicy waitpolicy,
 					   RangeVarGetRelidCallback callback, void *callback_arg)
 {
 	uint64		inval_count;
@@ -375,20 +381,28 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
 		 */
 		if (!OidIsValid(relId))
 			AcceptInvalidationMessages();
-		else if (!nowait)
+		else if (waitpolicy == LockWaitBlock)
 			LockRelationOid(relId, lockmode);
 		else if (!ConditionalLockRelationOid(relId, lockmode))
 		{
-			if (relation->schemaname)
-				ereport(ERROR,
-						(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
-						 errmsg("could not obtain lock on relation \"%s.%s\"",
-								relation->schemaname, relation->relname)));
-			else
-				ereport(ERROR,
+			/*
+               WaitNonBlock mode also sends InvalidOid upstream. Since no caller simultaneously
+			   requires NonBlock and missing_ok modes, this doesn't cause confusion.
+            */
+			if (waitpolicy == LockWaitNonBlock)
+				return InvalidOid;
+			else {
+				if (relation->schemaname)
+					ereport(ERROR,
 						(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
-						 errmsg("could not obtain lock on relation \"%s\"",
-								relation->relname)));
+							 errmsg("could not obtain lock on relation \"%s.%s\"",
+									relation->schemaname, relation->relname)));
+				else
+					ereport(ERROR,
+							(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+							 errmsg("could not obtain lock on relation \"%s\"",
+									relation->relname)));
+			}
 		}
 
 		/*
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index 175d1f3..edbd2e4 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -25,7 +25,7 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
-static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait);
+static Oid LockTableRecurse(Oid reloid, LOCKMODE lockmode, LockWaitPolicy waitpolicy, List *locked_oids);
 static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode);
 static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid,
 							 Oid oldrelid, void *arg);
@@ -37,6 +37,7 @@ void
 LockTableCommand(LockStmt *lockstmt)
 {
 	ListCell   *p;
+	bool		all_locked = false;
 
 	/*---------
 	 * During recovery we only accept these variations:
@@ -52,20 +53,83 @@ LockTableCommand(LockStmt *lockstmt)
 	/*
 	 * Iterate over the list and process the named relations one at a time
 	 */
-	foreach(p, lockstmt->relations)
-	{
-		RangeVar   *rv = (RangeVar *) lfirst(p);
-		bool		recurse = interpretInhOption(rv->inhOpt);
-		Oid			reloid;
+	do {
+		List	   *locked_oids = NIL;
+		List	   *failed_oids = NIL;
 
-		reloid = RangeVarGetRelidExtended(rv, lockstmt->mode, false,
-										  lockstmt->nowait,
-										  RangeVarCallbackForLockTable,
-										  (void *) &lockstmt->mode);
+		foreach(p, lockstmt->relations)
+		{
+			RangeVar   *rv = (RangeVar *) lfirst(p);
+			bool		recurse = interpretInhOption(rv->inhOpt);
+			Oid			reloid;
 
-		if (recurse)
-			LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
-	}
+			reloid = RangeVarGetRelidExtended(rv, lockstmt->mode, false,
+											  lockstmt->waitpolicy,
+											  RangeVarCallbackForLockTable,
+											  (void *) &lockstmt->mode);
+
+			/*
+			 * InvalidOid indicates the lock was not obtained.
+			 *
+			 * The loop is executed to completion in order to throw errors
+			 * early and setup a large number of targets for WaitForLockersMultiple().
+			 */
+			if (!OidIsValid(reloid)) {
+				reloid = RangeVarGetRelid(rv, NoLock, false);
+				failed_oids = lappend_oid(failed_oids, reloid);
+			}
+			else {
+				locked_oids = lappend_oid(locked_oids, reloid);
+
+				if (recurse) {
+					Oid		failed_oid;
+					failed_oid = LockTableRecurse(reloid, lockstmt->mode, lockstmt->waitpolicy, locked_oids);
+					if (OidIsValid(failed_oid)) {
+						failed_oids = lappend_oid(failed_oids, failed_oid);
+					}
+				}
+			}
+		}
+
+		/*
+		 * If some locks were not obtained carefully unlock all relations, including
+		 * inherited rels, and wait on all locktags discovered.
+		 */
+		if (list_length(failed_oids) == 0)
+			all_locked = true;
+		else {
+			List	   *lock_tags = NIL;
+			ListCell   *volatile cell;
+
+			/* Release lock like UnlockRelationOid() but keep the locktag */
+			foreach(cell, locked_oids) {
+				Oid			reloid = lfirst_oid(cell);
+				LOCKTAG		tag;
+
+				SetLocktagRelationOid(&tag, reloid);
+				LockRelease(&tag, lockstmt->mode, false);
+
+				/* Add unblocked tags to the list for this very cheap recheck */
+				lock_tags = lappend(lock_tags, &tag);
+			}
+
+			/* No locks to release, just make the list of tags */
+			foreach(cell, failed_oids) {
+				Oid			reloid = lfirst_oid(cell);
+				LOCKTAG		tag;
+
+				SetLocktagRelationOid(&tag, reloid);
+				lock_tags = lappend(lock_tags, &tag);
+			}
+
+			WaitForLockersMultiple(lock_tags, lockstmt->mode);
+
+			list_free(lock_tags);
+		}
+
+		list_free(locked_oids);
+		list_free(failed_oids);
+	} while (!all_locked);
 }
 
 /*
@@ -106,9 +170,12 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
  * We use find_inheritance_children not find_all_inheritors to avoid taking
  * locks far in advance of checking privileges.  This means we'll visit
  * multiply-inheriting children more than once, but that's no problem.
+ *
+ * In LockWaitNonBlock mode the return value is the Relation Oid which could
+ * not be locked.
  */
-static void
-LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
+static Oid
+LockTableRecurse(Oid reloid, LOCKMODE lockmode, LockWaitPolicy waitpolicy, List *locked_oids)
 {
 	List	   *children;
 	ListCell   *lc;
@@ -117,6 +184,7 @@ LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
 
 	foreach(lc, children)
 	{
+		Oid			lock_result;
 		Oid			childreloid = lfirst_oid(lc);
 		AclResult	aclresult;
 
@@ -132,7 +200,7 @@ LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
 		}
 
 		/* We have enough rights to lock the relation; do so. */
-		if (!nowait)
+		if (waitpolicy == LockWaitBlock)
 			LockRelationOid(childreloid, lockmode);
 		else if (!ConditionalLockRelationOid(childreloid, lockmode))
 		{
@@ -141,10 +209,14 @@ LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
 
 			if (!relname)
 				continue;		/* child concurrently dropped, just skip it */
-			ereport(ERROR,
-					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
-					 errmsg("could not obtain lock on relation \"%s\"",
-							relname)));
+
+			if (waitpolicy == LockWaitNonBlock)
+				return childreloid;
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						 errmsg("could not obtain lock on relation \"%s\"",
+								relname)));
 		}
 
 		/*
@@ -158,8 +230,18 @@ LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
 			continue;
 		}
 
-		LockTableRecurse(childreloid, lockmode, nowait);
+		/*
+		 * Locked children will be added to the locked_oids list to allow
+		 * caller to unlock obtained locks during waitpolicy LockWaitNonBlock
+		 */
+		lappend_oid(locked_oids, childreloid);
+
+		/* Attempt to lock the child table. Abandon loop if it fails */
+		lock_result = LockTableRecurse(childreloid, lockmode, waitpolicy, locked_oids);
+		if (OidIsValid(lock_result))
+			return lock_result;
 	}
+	return InvalidOid;
 }
 
 /*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index ac02304..8938828 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2304,6 +2304,9 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
 									 errmsg("could not obtain lock on row in relation \"%s\"",
 										RelationGetRelationName(relation))));
 						break;
+					case LockWaitNonBlock:
+						elog(ERROR, "unsupported lock wait_policy LockWaitNonBlock");
+						break;
 				}
 				continue;		/* loop back to repeat heap_fetch */
 			}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f4e4a91..4873e16 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3959,7 +3959,7 @@ _copyLockStmt(const LockStmt *from)
 
 	COPY_NODE_FIELD(relations);
 	COPY_SCALAR_FIELD(mode);
-	COPY_SCALAR_FIELD(nowait);
+	COPY_SCALAR_FIELD(waitpolicy);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 854c062..64ff060 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1962,7 +1962,7 @@ _equalLockStmt(const LockStmt *a, const LockStmt *b)
 {
 	COMPARE_NODE_FIELD(relations);
 	COMPARE_SCALAR_FIELD(mode);
-	COMPARE_SCALAR_FIELD(nowait);
+	COMPARE_SCALAR_FIELD(waitpolicy);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1273352..cf0b0a2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -289,8 +289,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <ival>	vacuum_option_list vacuum_option_elem
 %type <boolean>	opt_or_replace
 				opt_grant_grant_option opt_grant_admin_option
-				opt_nowait opt_if_exists opt_with_data
-%type <ival>	opt_nowait_or_skip
+				opt_if_exists opt_with_data
+%type <ival>	opt_nowait opt_nowait_or_deferrable opt_nowait_or_skip
 
 %type <list>	OptRoleList AlterOptRoleList
 %type <defelt>	CreateOptRoleElem AlterOptRoleElem
@@ -9712,13 +9712,13 @@ using_clause:
  *
  *****************************************************************************/
 
-LockStmt:	LOCK_P opt_table relation_expr_list opt_lock opt_nowait
+LockStmt:  LOCK_P opt_table relation_expr_list opt_lock opt_nowait_or_deferrable
 				{
 					LockStmt *n = makeNode(LockStmt);
 
 					n->relations = $3;
 					n->mode = $4;
-					n->nowait = $5;
+					n->waitpolicy = $5;
 					$$ = (Node *)n;
 				}
 		;
@@ -9737,8 +9737,14 @@ lock_type:	ACCESS SHARE					{ $$ = AccessShareLock; }
 			| ACCESS EXCLUSIVE				{ $$ = AccessExclusiveLock; }
 		;
 
-opt_nowait:	NOWAIT							{ $$ = TRUE; }
-			| /*EMPTY*/						{ $$ = FALSE; }
+opt_nowait:	NOWAIT							{ $$ = LockWaitError; }
+			| /*EMPTY*/						{ $$ = LockWaitBlock; }
+		;
+
+opt_nowait_or_deferrable:
+			NOWAIT							{ $$ = LockWaitError; }
+			| DEFERRABLE					{ $$ = LockWaitNonBlock; }
+			| /*EMPTY*/						{ $$ = LockWaitBlock; }
 		;
 
 opt_nowait_or_skip:
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 0632fc0..61c11a2 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -82,7 +82,7 @@ RelationInitLockInfo(Relation relation)
  * SetLocktagRelationOid
  *		Set up a locktag for a relation, given only relation OID
  */
-static inline void
+void
 SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
 {
 	Oid			dbid;
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 2ccb3a7..cf6dc72 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -14,6 +14,7 @@
 #ifndef NAMESPACE_H
 #define NAMESPACE_H
 
+#include "nodes/lockoptions.h"
 #include "nodes/primnodes.h"
 #include "storage/lock.h"
 
@@ -51,10 +52,10 @@ typedef void (*RangeVarGetRelidCallback) (const RangeVar *relation, Oid relId,
 										   Oid oldRelId, void *callback_arg);
 
 #define RangeVarGetRelid(relation, lockmode, missing_ok) \
-	RangeVarGetRelidExtended(relation, lockmode, missing_ok, false, NULL, NULL)
+	RangeVarGetRelidExtended(relation, lockmode, missing_ok, LockWaitBlock, NULL, NULL)
 
 extern Oid RangeVarGetRelidExtended(const RangeVar *relation,
-						 LOCKMODE lockmode, bool missing_ok, bool nowait,
+						 LOCKMODE lockmode, bool missing_ok, LockWaitPolicy waitpolicy,
 						 RangeVarGetRelidCallback callback,
 						 void *callback_arg);
 extern Oid	RangeVarGetCreationNamespace(const RangeVar *newRelation);
diff --git a/src/include/nodes/lockoptions.h b/src/include/nodes/lockoptions.h
index 1c2f00f..4e61c20 100644
--- a/src/include/nodes/lockoptions.h
+++ b/src/include/nodes/lockoptions.h
@@ -40,7 +40,9 @@ typedef enum LockWaitPolicy
 	/* Skip rows that can't be locked (SKIP LOCKED) */
 	LockWaitSkip,
 	/* Raise an error if a row cannot be locked (NOWAIT) */
-	LockWaitError
+	LockWaitError,
+	/* Non-Blocking wait. Always at the end of the queue. */
+	LockWaitNonBlock
 } LockWaitPolicy;
 
 #endif   /* LOCKOPTIONS_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 8b958b4..03b5212 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2906,7 +2906,7 @@ typedef struct LockStmt
 	NodeTag		type;
 	List	   *relations;		/* relations to lock */
 	int			mode;			/* lock mode */
-	bool		nowait;			/* no wait mode */
+	LockWaitPolicy		waitpolicy;			/* NOWAIT, DEFERRABLE, and blocking (default) options */
 } LockStmt;
 
 /* ----------------------
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 975b6f8..e82b684 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -98,6 +98,9 @@ extern void LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
 extern void UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
 							 LOCKMODE lockmode);
 
+/* Retrieve a locktag */
+extern void SetLocktagRelationOid(LOCKTAG *tag, Oid relid);
+
 /* Describe a locktag for error messages */
 extern void DescribeLockTag(StringInfo buf, const LOCKTAG *tag);
 
diff --git a/src/test/isolation/expected/lock-deferrable.out b/src/test/isolation/expected/lock-deferrable.out
new file mode 100644
index 0000000..10e13fe
--- /dev/null
+++ b/src/test/isolation/expected/lock-deferrable.out
@@ -0,0 +1,28 @@
+Parsed test spec with 3 sessions
+
+starting permutation: s1a s2a s3a s1b s3b s2b
+step s1a: LOCK TABLE foo;
+step s2a: LOCK TABLE foo DEFERRABLE; <waiting ...>
+step s3a: LOCK TABLE foo2; <waiting ...>
+step s1b: COMMIT;
+step s3a: <... completed>
+step s3b: COMMIT;
+step s2a: <... completed>
+step s2b: COMMIT;
+
+starting permutation: s3a s2a s1a s3b s1b s2b
+step s3a: LOCK TABLE foo2;
+step s2a: LOCK TABLE foo DEFERRABLE; <waiting ...>
+step s1a: LOCK TABLE foo; <waiting ...>
+step s3b: COMMIT;
+step s1a: <... completed>
+step s1b: COMMIT;
+step s2a: <... completed>
+step s2b: COMMIT;
+
+starting permutation: s2a s3a s2b s3b
+step s2a: LOCK TABLE foo DEFERRABLE;
+step s3a: LOCK TABLE foo2; <waiting ...>
+step s2b: COMMIT;
+step s3a: <... completed>
+step s3b: COMMIT;
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 138a0b7..0434610 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -48,3 +48,4 @@ test: alter-table-3
 test: create-trigger
 test: async-notify
 test: timeouts
+test: lock-deferrable
diff --git a/src/test/isolation/specs/lock-deferrable.spec b/src/test/isolation/specs/lock-deferrable.spec
new file mode 100644
index 0000000..88ecaa9
--- /dev/null
+++ b/src/test/isolation/specs/lock-deferrable.spec
@@ -0,0 +1,39 @@
+# Test NOWAIT when regular row locks can't be acquired.
+
+setup
+{
+  CREATE TABLE foo (
+	id int
+  );
+  CREATE TABLE foo2 () INHERITS (foo);
+}
+
+teardown
+{
+  DROP TABLE foo CASCADE;
+}
+
+session "s1"
+setup		{ BEGIN; }
+step "s1a"	{ LOCK TABLE foo; }
+step "s1b"	{ COMMIT; }
+
+session "s2"
+setup		{ BEGIN; }
+step "s2a"	{ LOCK TABLE foo DEFERRABLE; }
+step "s2b"	{ COMMIT; }
+
+session "s3"
+setup		{ BEGIN; }
+step "s3a"	{ LOCK TABLE foo2; }
+step "s3b"	{ COMMIT; }
+
+
+# LOCK DEFERRABLE should not block other processes
+# but is itself blocked. Locks cascade to child tables.
+permutation "s1a" "s2a" "s3a" "s1b" "s3b" "s2b"
+permutation "s3a" "s2a" "s1a" "s3b" "s1b" "s2b"
+
+# LOCK DEFERRABLE blocks when lock is obtained
+permutation "s2a" "s3a" "s2b" "s3b"
+
diff --git a/src/test/regress/expected/lock.out b/src/test/regress/expected/lock.out
index fd27344..252bd1f 100644
--- a/src/test/regress/expected/lock.out
+++ b/src/test/regress/expected/lock.out
@@ -33,6 +33,19 @@ LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE NOWAIT;
 LOCK TABLE lock_view1 IN EXCLUSIVE MODE;   -- Will fail; can't lock a non-table
 ERROR:  "lock_view1" is not a table
 ROLLBACK;
+-- Try using DEFERRABLE along with valid options.
+BEGIN TRANSACTION;
+LOCK TABLE lock_tbl1 IN ACCESS SHARE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN ROW SHARE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN ROW EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN SHARE UPDATE EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN SHARE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN SHARE ROW EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_view1 IN EXCLUSIVE MODE;   -- Will fail; can't lock a non-table
+ERROR:  "lock_view1" is not a table
+ROLLBACK;
 -- Verify that we can lock a table with inheritance children.
 CREATE TABLE lock_tbl2 (b BIGINT) INHERITS (lock_tbl1);
 CREATE TABLE lock_tbl3 () INHERITS (lock_tbl2);
diff --git a/src/test/regress/sql/lock.sql b/src/test/regress/sql/lock.sql
index 567e8bc..82611dd 100644
--- a/src/test/regress/sql/lock.sql
+++ b/src/test/regress/sql/lock.sql
@@ -36,6 +36,19 @@ LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE NOWAIT;
 LOCK TABLE lock_view1 IN EXCLUSIVE MODE;   -- Will fail; can't lock a non-table
 ROLLBACK;
 
+-- Try using DEFERRABLE along with valid options.
+BEGIN TRANSACTION;
+LOCK TABLE lock_tbl1 IN ACCESS SHARE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN ROW SHARE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN ROW EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN SHARE UPDATE EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN SHARE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN SHARE ROW EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE DEFERRABLE;
+LOCK TABLE lock_view1 IN EXCLUSIVE MODE;   -- Will fail; can't lock a non-table
+ROLLBACK;
+
 -- Verify that we can lock a table with inheritance children.
 CREATE TABLE lock_tbl2 (b BIGINT) INHERITS (lock_tbl1);
 CREATE TABLE lock_tbl3 () INHERITS (lock_tbl2);
