diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 1b48b48e097a96e2282ebf5f59508e3e20383c27..68f23177eba5d5a7d6826920c65e503ea3554c72 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -160,12 +160,10 @@ static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
 #endif
-  if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
-    /* This ref is dropped if grpc_mdelem_unref reaches 1,
-       but allows us to safely unref without taking the mdctx lock
-       until such time */
-    gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
+  if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) {
     md->context->mdtab_free--;
+  } else {
+    GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
   }
 }
 
@@ -537,7 +535,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
      this function - meaning that no adjustment to mdtab_free is necessary,
      simplifying the logic here to be just an atomic increment */
   /* use C assert to have this removed in opt builds */
-  assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+  assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2);
   gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
   return gmd;
 }
@@ -555,8 +553,10 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
   if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
     grpc_mdctx *ctx = md->context;
     lock(ctx);
-    GPR_ASSERT(1 == gpr_atm_full_fetch_add(&md->refcnt, -1));
-    ctx->mdtab_free++;
+    if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
+      ctx->mdtab_free++;
+      gpr_atm_no_barrier_store(&md->refcnt, 0);
+    }
     unlock(ctx);
   }
 }