* further if a longer lived reference is needed.
     */
    pg_atomic_init_u32(&shhashent->refcount, 1);
+
+   /*
+    * Initialize "generation" to 0, as freshly created.
+    */
+   pg_atomic_init_u32(&shhashent->generation, 0);
    shhashent->dropped = false;
 
    chunk = dsa_allocate0(pgStatLocal.dsa, pgstat_get_kind_info(kind)->shared_size);
 
    /* mark as not dropped anymore */
    pg_atomic_fetch_add_u32(&shhashent->refcount, 1);
+
+   /*
+    * Increment "generation", to let any backend with local references know
+    * that what they point to is outdated.
+    */
+   pg_atomic_fetch_add_u32(&shhashent->generation, 1);
    shhashent->dropped = false;
 
    /* reinitialize content */
 
    entry_ref->shared_stats = shheader;
    entry_ref->shared_entry = shhashent;
+   entry_ref->generation = pg_atomic_read_u32(&shhashent->generation);
 }
 
 /*
             * case are replication slot stats, where a new slot can be
             * created with the same index just after dropping. But oid
             * wraparound can lead to other cases as well. We just reset the
-            * stats to their plain state.
+            * stats to their plain state, while incrementing its "generation"
+            * in the shared entry for any remaining local references.
             */
            shheader = pgstat_reinit_entry(kind, shhashent);
            pgstat_acquire_entry_ref(entry_ref, shhashent, shheader);
            if (!shent)
                elog(ERROR, "could not find just referenced shared stats entry");
 
-           Assert(pg_atomic_read_u32(&entry_ref->shared_entry->refcount) == 0);
-           Assert(entry_ref->shared_entry == shent);
-
-           pgstat_free_entry(shent, NULL);
+           /*
+            * This entry may have been reinitialized while trying to release
+            * it, so double-check that it has not been reused while holding a
+            * lock on its shared entry.
+            */
+           if (pg_atomic_read_u32(&entry_ref->shared_entry->generation) ==
+               entry_ref->generation)
+           {
+               /* Same "generation", so we're OK with the removal */
+               Assert(pg_atomic_read_u32(&entry_ref->shared_entry->refcount) == 0);
+               Assert(entry_ref->shared_entry == shent);
+               pgstat_free_entry(shent, NULL);
+           }
+           else
+           {
+               /*
+                * Shared stats entry has been reinitialized, so do not drop
+                * its shared entry, only release its lock.
+                */
+               dshash_release_lock(pgStatLocal.shared_hash, shent);
+           }
        }
    }
 
 
     */
    pg_atomic_uint32 refcount;
 
+   /*
+    * Counter tracking the number of times the entry has been reused.
+    *
+    * Set to 0 when the entry is created, and incremented by one each time
+    * the shared entry is reinitialized with pgstat_reinit_entry().
+    *
+    * May only be incremented / decremented while holding at least a shared
+    * lock on the dshash partition containing the entry. Like refcount, it
+    * needs to be an atomic variable because multiple backends can increment
+    * the generation with just a shared lock.
+    */
+   pg_atomic_uint32 generation;
+
    /*
     * Pointer to shared stats. The stats entry always starts with
     * PgStatShared_Common, embedded in a larger struct containing the
     */
    PgStatShared_Common *shared_stats;
 
+   /*
+    * Copy of PgStatShared_HashEntry->generation, keeping locally track of
+    * the shared stats entry "generation" retrieved (number of times reused).
+    */
+   uint32      generation;
+
    /*
     * Pending statistics data that will need to be flushed to shared memory
     * stats eventually. Each stats kind utilizing pending data defines what