diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts
index 56011d06359..8daf68c27c8 100644
--- a/packages/runtime-core/__tests__/hydration.spec.ts
+++ b/packages/runtime-core/__tests__/hydration.spec.ts
@@ -2299,6 +2299,16 @@ describe('SSR hydration', () => {
       expect(`Hydration node mismatch`).not.toHaveBeenWarned()
     })
 
+    test('comment mismatch (v-if)', () => {
+      const { container } = mountWithHydration(`<!--v-if-->`, () =>
+        h('div', { 'data-allow-mismatch': '' }, [h('span', 'value')]),
+      )
+      expect(container.innerHTML).toBe(
+        '<div data-allow-mismatch=""><span>value</span></div>',
+      )
+      expect(`Hydration node mismatch`).not.toHaveBeenWarned()
+    })
+
     test('comment mismatch (text)', () => {
       const { container } = mountWithHydration(
         `<div data-allow-mismatch="children">foobar</div>`,
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index a94ff356810..3977b45a1d2 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -19,6 +19,7 @@ import {
   ShapeFlags,
   def,
   getEscapedCssVarName,
+  hasOwn,
   includeBooleanAttr,
   isBooleanAttr,
   isKnownHtmlAttr,
@@ -675,7 +676,10 @@ export function createHydrationFunctions(
     slotScopeIds: string[] | null,
     isFragment: boolean,
   ): Node | null => {
-    if (!isMismatchAllowed(node.parentElement!, MismatchTypes.CHILDREN)) {
+    if (
+      !isMismatchAllowed(node.parentElement!, MismatchTypes.CHILDREN) &&
+      !isMismatchAllowedForCommentNode(node, vnode)
+    ) {
       ;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
         warn(
           `Hydration node mismatch:\n- rendered on server:`,
@@ -993,3 +997,11 @@ function isMismatchAllowed(
     return allowedAttr.split(',').includes(MismatchTypeString[allowedType])
   }
 }
+
+// data-allow-mismatch + v-if
+function isMismatchAllowedForCommentNode(
+  node: Node,
+  { props }: VNode,
+): boolean {
+  return isComment(node) && props != null && hasOwn(props, allowMismatchAttr)
+}