diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js
index f6e6d3222b90a..4f65ecf241c80 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzSuppressHydrationWarning-test.js
@@ -248,9 +248,10 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
         ]);
       }).toErrorDev(
         [
+          'Expected server HTML to contain a matching <span> in <span>',
           'An error occurred during hydration. The server HTML was replaced with client content in <div>.',
         ],
-        {withoutStack: true},
+        {withoutStack: 1},
       );
     } else {
       // This used to not warn.
@@ -336,9 +337,10 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
         ]);
       }).toErrorDev(
         [
+          'Did not expect server HTML to contain the text node "Server" in <span>',
           'An error occurred during hydration. The server HTML was replaced with client content in <div>.',
         ],
-        {withoutStack: true},
+        {withoutStack: 1},
       );
     } else {
       // This used to not warn.
@@ -389,9 +391,10 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
         ]);
       }).toErrorDev(
         [
+          'Expected server HTML to contain a matching text node for "Client" in <span>.',
           'An error occurred during hydration. The server HTML was replaced with client content in <div>.',
         ],
-        {withoutStack: true},
+        {withoutStack: 1},
       );
     } else {
       // This used to not warn.
@@ -445,9 +448,10 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
         ]);
       }).toErrorDev(
         [
+          'Did not expect server HTML to contain the text node "Server" in <span>.',
           'An error occurred during hydration. The server HTML was replaced with client content in <div>.',
         ],
-        {withoutStack: true},
+        {withoutStack: 1},
       );
     } else {
       // This used to not warn.
@@ -500,9 +504,10 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
         ]);
       }).toErrorDev(
         [
+          'Expected server HTML to contain a matching text node for "Client" in <span>.',
           'An error occurred during hydration. The server HTML was replaced with client content in <div>.',
         ],
-        {withoutStack: true},
+        {withoutStack: 1},
       );
     } else {
       // This used to not warn.
@@ -630,9 +635,10 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
         ]);
       }).toErrorDev(
         [
+          'Expected server HTML to contain a matching <p> in <div>.',
           'An error occurred during hydration. The server HTML was replaced with client content in <div>.',
         ],
-        {withoutStack: true},
+        {withoutStack: 1},
       );
     } else {
       // This used to not warn.
@@ -681,9 +687,10 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
         ]);
       }).toErrorDev(
         [
+          'Did not expect server HTML to contain a <p> in <div>.',
           'An error occurred during hydration. The server HTML was replaced with client content in <div>.',
         ],
-        {withoutStack: true},
+        {withoutStack: 1},
       );
     } else {
       // This used to not warn.
diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js
index 925f7088e4b04..d27bdff4305ab 100644
--- a/packages/react-dom/src/client/ReactDOMHostConfig.js
+++ b/packages/react-dom/src/client/ReactDOMHostConfig.js
@@ -62,6 +62,7 @@ import dangerousStyleValue from '../shared/dangerousStyleValue';
 import {retryIfBlockedOn} from '../events/ReactDOMEventReplaying';
 
 import {
+  enableClientRenderFallbackOnHydrationMismatch,
   enableSuspenseServerRenderer,
   enableCreateEventHandleAPI,
   enableScopeAPI,
@@ -1004,14 +1005,20 @@ export function didNotHydrateInstance(
   parentProps: Props,
   parentInstance: Instance,
   instance: HydratableInstance,
+  isConcurrentMode: boolean,
 ) {
-  if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
-    if (instance.nodeType === ELEMENT_NODE) {
-      warnForDeletedHydratableElement(parentInstance, (instance: any));
-    } else if (instance.nodeType === COMMENT_NODE) {
-      // TODO: warnForDeletedHydratableSuspenseBoundary
-    } else {
-      warnForDeletedHydratableText(parentInstance, (instance: any));
+  if (__DEV__) {
+    if (
+      (enableClientRenderFallbackOnHydrationMismatch && isConcurrentMode) ||
+      parentProps[SUPPRESS_HYDRATION_WARNING] !== true
+    ) {
+      if (instance.nodeType === ELEMENT_NODE) {
+        warnForDeletedHydratableElement(parentInstance, (instance: any));
+      } else if (instance.nodeType === COMMENT_NODE) {
+        // TODO: warnForDeletedHydratableSuspenseBoundary
+      } else {
+        warnForDeletedHydratableText(parentInstance, (instance: any));
+      }
     }
   }
 }
@@ -1082,9 +1089,15 @@ export function didNotFindHydratableInstance(
   parentInstance: Instance,
   type: string,
   props: Props,
+  isConcurrentMode: boolean,
 ) {
-  if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
-    warnForInsertedHydratedElement(parentInstance, type, props);
+  if (__DEV__) {
+    if (
+      (enableClientRenderFallbackOnHydrationMismatch && isConcurrentMode) ||
+      parentProps[SUPPRESS_HYDRATION_WARNING] !== true
+    ) {
+      warnForInsertedHydratedElement(parentInstance, type, props);
+    }
   }
 }
 
@@ -1093,9 +1106,15 @@ export function didNotFindHydratableTextInstance(
   parentProps: Props,
   parentInstance: Instance,
   text: string,
+  isConcurrentMode: boolean,
 ) {
-  if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
-    warnForInsertedHydratedText(parentInstance, text);
+  if (__DEV__) {
+    if (
+      (enableClientRenderFallbackOnHydrationMismatch && isConcurrentMode) ||
+      parentProps[SUPPRESS_HYDRATION_WARNING] !== true
+    ) {
+      warnForInsertedHydratedText(parentInstance, text);
+    }
   }
 }
 
@@ -1104,7 +1123,7 @@ export function didNotFindHydratableSuspenseInstance(
   parentProps: Props,
   parentInstance: Instance,
 ) {
-  if (__DEV__ && parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
+  if (__DEV__) {
     // TODO: warnForInsertedHydratedSuspense(parentInstance);
   }
 }
diff --git a/packages/react-reconciler/src/ReactFiberHydrationContext.new.js b/packages/react-reconciler/src/ReactFiberHydrationContext.new.js
index 6a7a175d6cff3..94ca9e61eec15 100644
--- a/packages/react-reconciler/src/ReactFiberHydrationContext.new.js
+++ b/packages/react-reconciler/src/ReactFiberHydrationContext.new.js
@@ -148,21 +148,26 @@ function warnUnhydratedInstance(
 ) {
   if (__DEV__) {
     switch (returnFiber.tag) {
-      case HostRoot:
+      case HostRoot: {
         didNotHydrateInstanceWithinContainer(
           returnFiber.stateNode.containerInfo,
           instance,
         );
         break;
-      case HostComponent:
+      }
+      case HostComponent: {
+        const isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;
         didNotHydrateInstance(
           returnFiber.type,
           returnFiber.memoizedProps,
           returnFiber.stateNode,
           instance,
+          // TODO: Delete this argument when we remove the legacy root API.
+          isConcurrentMode,
         );
         break;
-      case SuspenseComponent:
+      }
+      case SuspenseComponent: {
         const suspenseState: SuspenseState = returnFiber.memoizedState;
         if (suspenseState.dehydrated !== null)
           didNotHydrateInstanceWithinSuspenseInstance(
@@ -170,6 +175,7 @@ function warnUnhydratedInstance(
             instance,
           );
         break;
+      }
     }
   }
 }
@@ -234,33 +240,44 @@ function warnNonhydratedInstance(returnFiber: Fiber, fiber: Fiber) {
         const parentProps = returnFiber.memoizedProps;
         const parentInstance = returnFiber.stateNode;
         switch (fiber.tag) {
-          case HostComponent:
+          case HostComponent: {
             const type = fiber.type;
             const props = fiber.pendingProps;
+            const isConcurrentMode =
+              (returnFiber.mode & ConcurrentMode) !== NoMode;
             didNotFindHydratableInstance(
               parentType,
               parentProps,
               parentInstance,
               type,
               props,
+              // TODO: Delete this argument when we remove the legacy root API.
+              isConcurrentMode,
             );
             break;
-          case HostText:
+          }
+          case HostText: {
             const text = fiber.pendingProps;
+            const isConcurrentMode =
+              (returnFiber.mode & ConcurrentMode) !== NoMode;
             didNotFindHydratableTextInstance(
               parentType,
               parentProps,
               parentInstance,
               text,
+              // TODO: Delete this argument when we remove the legacy root API.
+              isConcurrentMode,
             );
             break;
-          case SuspenseComponent:
+          }
+          case SuspenseComponent: {
             didNotFindHydratableSuspenseInstance(
               parentType,
               parentProps,
               parentInstance,
             );
             break;
+          }
         }
         break;
       }
@@ -476,10 +493,11 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): boolean {
     // hydration parent is the parent host component of this host text.
     const returnFiber = hydrationParentFiber;
     if (returnFiber !== null) {
-      const isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;
       switch (returnFiber.tag) {
         case HostRoot: {
           const parentContainer = returnFiber.stateNode.containerInfo;
+          const isConcurrentMode =
+            (returnFiber.mode & ConcurrentMode) !== NoMode;
           didNotMatchHydratedContainerTextInstance(
             parentContainer,
             textInstance,
@@ -493,6 +511,8 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): boolean {
           const parentType = returnFiber.type;
           const parentProps = returnFiber.memoizedProps;
           const parentInstance = returnFiber.stateNode;
+          const isConcurrentMode =
+            (returnFiber.mode & ConcurrentMode) !== NoMode;
           didNotMatchHydratedTextInstance(
             parentType,
             parentProps,
diff --git a/packages/react-reconciler/src/ReactFiberHydrationContext.old.js b/packages/react-reconciler/src/ReactFiberHydrationContext.old.js
index 8c334924943ab..6af68fe66a79d 100644
--- a/packages/react-reconciler/src/ReactFiberHydrationContext.old.js
+++ b/packages/react-reconciler/src/ReactFiberHydrationContext.old.js
@@ -148,21 +148,26 @@ function warnUnhydratedInstance(
 ) {
   if (__DEV__) {
     switch (returnFiber.tag) {
-      case HostRoot:
+      case HostRoot: {
         didNotHydrateInstanceWithinContainer(
           returnFiber.stateNode.containerInfo,
           instance,
         );
         break;
-      case HostComponent:
+      }
+      case HostComponent: {
+        const isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;
         didNotHydrateInstance(
           returnFiber.type,
           returnFiber.memoizedProps,
           returnFiber.stateNode,
           instance,
+          // TODO: Delete this argument when we remove the legacy root API.
+          isConcurrentMode,
         );
         break;
-      case SuspenseComponent:
+      }
+      case SuspenseComponent: {
         const suspenseState: SuspenseState = returnFiber.memoizedState;
         if (suspenseState.dehydrated !== null)
           didNotHydrateInstanceWithinSuspenseInstance(
@@ -170,6 +175,7 @@ function warnUnhydratedInstance(
             instance,
           );
         break;
+      }
     }
   }
 }
@@ -234,33 +240,44 @@ function warnNonhydratedInstance(returnFiber: Fiber, fiber: Fiber) {
         const parentProps = returnFiber.memoizedProps;
         const parentInstance = returnFiber.stateNode;
         switch (fiber.tag) {
-          case HostComponent:
+          case HostComponent: {
             const type = fiber.type;
             const props = fiber.pendingProps;
+            const isConcurrentMode =
+              (returnFiber.mode & ConcurrentMode) !== NoMode;
             didNotFindHydratableInstance(
               parentType,
               parentProps,
               parentInstance,
               type,
               props,
+              // TODO: Delete this argument when we remove the legacy root API.
+              isConcurrentMode,
             );
             break;
-          case HostText:
+          }
+          case HostText: {
             const text = fiber.pendingProps;
+            const isConcurrentMode =
+              (returnFiber.mode & ConcurrentMode) !== NoMode;
             didNotFindHydratableTextInstance(
               parentType,
               parentProps,
               parentInstance,
               text,
+              // TODO: Delete this argument when we remove the legacy root API.
+              isConcurrentMode,
             );
             break;
-          case SuspenseComponent:
+          }
+          case SuspenseComponent: {
             didNotFindHydratableSuspenseInstance(
               parentType,
               parentProps,
               parentInstance,
             );
             break;
+          }
         }
         break;
       }
@@ -476,10 +493,11 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): boolean {
     // hydration parent is the parent host component of this host text.
     const returnFiber = hydrationParentFiber;
     if (returnFiber !== null) {
-      const isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;
       switch (returnFiber.tag) {
         case HostRoot: {
           const parentContainer = returnFiber.stateNode.containerInfo;
+          const isConcurrentMode =
+            (returnFiber.mode & ConcurrentMode) !== NoMode;
           didNotMatchHydratedContainerTextInstance(
             parentContainer,
             textInstance,
@@ -493,6 +511,8 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): boolean {
           const parentType = returnFiber.type;
           const parentProps = returnFiber.memoizedProps;
           const parentInstance = returnFiber.stateNode;
+          const isConcurrentMode =
+            (returnFiber.mode & ConcurrentMode) !== NoMode;
           didNotMatchHydratedTextInstance(
             parentType,
             parentProps,