{
            if (entry->localreloid == reloid)
            {
-               entry->localreloid = InvalidOid;
+               entry->localrelvalid = false;
                hash_seq_term(&status);
                break;
            }
        hash_seq_init(&status, LogicalRepRelMap);
 
        while ((entry = (LogicalRepRelMapEntry *) hash_seq_search(&status)) != NULL)
-           entry->localreloid = InvalidOid;
+           entry->localrelvalid = false;
    }
 }
 
 /*
  * Open the local relation associated with the remote one.
  *
- * Optionally rebuilds the Relcache mapping if it was invalidated
- * by local DDL.
+ * Rebuilds the Relcache mapping if it was invalidated by local DDL.
  */
 LogicalRepRelMapEntry *
 logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 {
    LogicalRepRelMapEntry *entry;
    bool        found;
-   Oid         relid = InvalidOid;
    LogicalRepRelation *remoterel;
 
    if (LogicalRepRelMap == NULL)
 
    remoterel = &entry->remoterel;
 
+   /* Ensure we don't leak a relcache refcount. */
+   if (entry->localrel)
+       elog(ERROR, "remote relation ID %u is already open", remoteid);
+
    /*
     * When opening and locking a relation, pending invalidation messages are
-    * processed which can invalidate the relation.  We need to update the
-    * local cache both when we are first time accessing the relation and when
-    * the relation is invalidated (aka entry->localreloid is set InvalidOid).
+    * processed which can invalidate the relation.  Hence, if the entry is
+    * currently considered valid, try to open the local relation by OID and
+    * see if invalidation ensues.
     */
-   if (!OidIsValid(entry->localreloid))
+   if (entry->localrelvalid)
    {
+       entry->localrel = try_relation_open(entry->localreloid, lockmode);
+       if (!entry->localrel)
+       {
+           /* Table was renamed or dropped. */
+           entry->localrelvalid = false;
+       }
+       else if (!entry->localrelvalid)
+       {
+           /* Note we release the no-longer-useful lock here. */
+           heap_close(entry->localrel, lockmode);
+           entry->localrel = NULL;
+       }
+   }
+
+   /*
+    * If the entry has been marked invalid since we last had lock on it,
+    * re-open the local relation by name and rebuild all derived data.
+    */
+   if (!entry->localrelvalid)
+   {
+       Oid         relid;
+       int         found;
+       Bitmapset  *idkey;
+       TupleDesc   desc;
+       MemoryContext oldctx;
+       int         i;
+
        /* Try to find and lock the relation by name. */
        relid = RangeVarGetRelid(makeRangeVar(remoterel->nspname,
                                              remoterel->relname, -1),
                     errmsg("logical replication target relation \"%s.%s\" does not exist",
                            remoterel->nspname, remoterel->relname)));
        entry->localrel = heap_open(relid, NoLock);
-
-   }
-   else
-   {
-       relid = entry->localreloid;
-       entry->localrel = heap_open(entry->localreloid, lockmode);
-   }
-
-   if (!OidIsValid(entry->localreloid))
-   {
-       int         found;
-       Bitmapset  *idkey;
-       TupleDesc   desc;
-       MemoryContext oldctx;
-       int         i;
+       entry->localreloid = relid;
 
        /* Check for supported relkind. */
        CheckSubscriptionRelkind(entry->localrel->rd_rel->relkind,
            }
        }
 
-       entry->localreloid = relid;
+       entry->localrelvalid = true;
    }
 
    if (entry->state != SUBREL_STATE_READY)