diff --git a/e2e/support/helpers/e2e-ad-hoc-question-helpers.js b/e2e/support/helpers/e2e-ad-hoc-question-helpers.js
index 884402bfd48d7df3625b6a4eb6eef4041343b743..041e548811d43ea2435b86073e27713fb3d3864e 100644
--- a/e2e/support/helpers/e2e-ad-hoc-question-helpers.js
+++ b/e2e/support/helpers/e2e-ad-hoc-question-helpers.js
@@ -66,7 +66,7 @@ export function startNewNativeQuestion(alias = "editor") {
  */
 export function visitQuestionAdhoc(
   question,
-  { callback, mode, autorun = true } = {},
+  { callback, mode, autorun = true, skipWaiting = false } = {},
 ) {
   const questionMode = mode === "notebook" ? "/notebook" : "";
 
@@ -78,7 +78,7 @@ export function visitQuestionAdhoc(
 
   runQueryIfNeeded(question, autorun);
 
-  if (mode !== "notebook") {
+  if (mode !== "notebook" && !skipWaiting) {
     cy.wait("@" + alias).then(xhr => callback && callback(xhr));
   }
 }
diff --git a/e2e/test/scenarios/question/document-title.cy.spec.js b/e2e/test/scenarios/question/document-title.cy.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..9b1ed6a9e02360ab281fd0a06e5e3b1bb10b297d
--- /dev/null
+++ b/e2e/test/scenarios/question/document-title.cy.spec.js
@@ -0,0 +1,28 @@
+import { restore, visitQuestionAdhoc } from "e2e/support/helpers";
+
+const PG_DB_ID = 2;
+describe("question loading changes document title", () => {
+  beforeEach(() => {
+    restore("postgres-12");
+    cy.signInAsNormalUser();
+  });
+
+  it("should verify document title changes while loading a slow question (metabase#40051)", () => {
+    cy.log("run a slow question");
+
+    visitQuestionAdhoc(
+      {
+        dataset_query: {
+          type: "native",
+          native: {
+            query: "select pg_sleep(60)",
+          },
+          database: PG_DB_ID,
+        },
+      },
+      { skipWaiting: true },
+    );
+
+    cy.title().should("eq", "Doing science... · Metabase");
+  });
+});
diff --git a/enterprise/frontend/src/metabase-enterprise/whitelabel/index.js b/enterprise/frontend/src/metabase-enterprise/whitelabel/index.js
index 57e921fede644ccdfda5bb56a30e8fa569bc202f..920edb2a905aa3be06691b4d1db456b870207c15 100644
--- a/enterprise/frontend/src/metabase-enterprise/whitelabel/index.js
+++ b/enterprise/frontend/src/metabase-enterprise/whitelabel/index.js
@@ -2,7 +2,7 @@ import { t } from "ttag";
 
 import MetabaseSettings from "metabase/lib/settings";
 import {
-  PLUGIN_APP_INIT_FUCTIONS,
+  PLUGIN_APP_INIT_FUNCTIONS,
   PLUGIN_LANDING_PAGE,
   PLUGIN_LOGO_ICON_COMPONENTS,
   PLUGIN_ADMIN_SETTINGS_UPDATES,
@@ -124,7 +124,7 @@ if (hasPremiumFeature("whitelabel")) {
     ...sections,
   }));
 
-  PLUGIN_APP_INIT_FUCTIONS.push(() => {
+  PLUGIN_APP_INIT_FUNCTIONS.push(() => {
     updateColors();
     MetabaseSettings.on("application-colors", updateColors);
   });
@@ -133,7 +133,7 @@ if (hasPremiumFeature("whitelabel")) {
   PLUGIN_SELECTORS.canWhitelabel = () => true;
 
   // these selectors control whitelabeling UI
-  PLUGIN_SELECTORS.getLoadingMessage = getLoadingMessage;
+  PLUGIN_SELECTORS.getLoadingMessageFactory = getLoadingMessage;
   PLUGIN_SELECTORS.getIsWhiteLabeling = getIsWhiteLabeling;
   PLUGIN_SELECTORS.getApplicationName = getApplicationName;
   PLUGIN_SELECTORS.getShowMetabaseLinks = getShowMetabaseLinks;
diff --git a/frontend/src/metabase/app.js b/frontend/src/metabase/app.js
index 8cc0f77e906293d468bd9461e2e34f3d242c25ba..53ce42e0a19b8ddb9dc7dfc7da5aff59dc6d6515 100644
--- a/frontend/src/metabase/app.js
+++ b/frontend/src/metabase/app.js
@@ -42,7 +42,7 @@ import { createTracker } from "metabase/lib/analytics";
 import api from "metabase/lib/api";
 import { initializeEmbedding } from "metabase/lib/embed";
 import MetabaseSettings from "metabase/lib/settings";
-import { PLUGIN_APP_INIT_FUCTIONS } from "metabase/plugins";
+import { PLUGIN_APP_INIT_FUNCTIONS } from "metabase/plugins";
 import { refreshSiteSettings } from "metabase/redux/settings";
 import { EmotionCacheProvider } from "metabase/styled-components/components/EmotionCacheProvider";
 import GlobalStyles from "metabase/styled-components/containers/GlobalStyles";
@@ -90,7 +90,7 @@ function _init(reducers, getRoutes, callback) {
 
   store.dispatch(refreshSiteSettings());
 
-  PLUGIN_APP_INIT_FUCTIONS.forEach(init => init({ root }));
+  PLUGIN_APP_INIT_FUNCTIONS.forEach(init => init({ root }));
 
   window.Metabase = window.Metabase || {};
   window.Metabase.store = store;
diff --git a/frontend/src/metabase/plugins/index.ts b/frontend/src/metabase/plugins/index.ts
index 2b3469989056f686d9f892cccaa2d21ad307ffd6..5e4354018f67a4ecde0ae9f17bb98f2b352cf6c7 100644
--- a/frontend/src/metabase/plugins/index.ts
+++ b/frontend/src/metabase/plugins/index.ts
@@ -33,7 +33,7 @@ import type { AdminPathKey, State } from "metabase-types/store";
 import type { GetAuthProviders, PluginGroupManagersType } from "./types";
 
 // functions called when the application is started
-export const PLUGIN_APP_INIT_FUCTIONS = [];
+export const PLUGIN_APP_INIT_FUNCTIONS = [];
 
 // function to determine the landing page
 export const PLUGIN_LANDING_PAGE = [];
@@ -146,7 +146,7 @@ export const PLUGIN_IS_PASSWORD_USER: ((user: User) => boolean)[] = [];
 // selectors that customize behavior between app versions
 export const PLUGIN_SELECTORS = {
   canWhitelabel: (_state: State) => false,
-  getLoadingMessage: (_state: State) => (isSlow: boolean) =>
+  getLoadingMessageFactory: (_state: State) => (isSlow: boolean) =>
     isSlow ? t`Waiting for results...` : t`Doing science...`,
   getIsWhiteLabeling: (_state: State) => false,
   getApplicationName: (_state: State) => "Metabase",
diff --git a/frontend/src/metabase/query_builder/actions/querying.js b/frontend/src/metabase/query_builder/actions/querying.js
index ab0af65a33763cbe53bafc83eefc4ac715d48ef0..dc7b4054c455ca2307a749a8a1c217b81c10ddb1 100644
--- a/frontend/src/metabase/query_builder/actions/querying.js
+++ b/frontend/src/metabase/query_builder/actions/querying.js
@@ -5,7 +5,7 @@ import * as MetabaseAnalytics from "metabase/lib/analytics";
 import { startTimer } from "metabase/lib/performance";
 import { defer } from "metabase/lib/promise";
 import { createThunkAction } from "metabase/lib/redux";
-import { getWhiteLabeledLoadingMessage } from "metabase/selectors/whitelabel";
+import { getWhiteLabeledLoadingMessageFactory } from "metabase/selectors/whitelabel";
 import { runQuestionQuery as apiRunQuestionQuery } from "metabase/services";
 import { getSensibleDisplays } from "metabase/visualizations";
 import * as Lib from "metabase-lib";
@@ -146,7 +146,9 @@ export const runQuestionQuery = ({
 const loadStartUIControls = createThunkAction(
   LOAD_START_UI_CONTROLS,
   () => (dispatch, getState) => {
-    const loadingMessage = getWhiteLabeledLoadingMessage(getState());
+    const getLoadingMessage = getWhiteLabeledLoadingMessageFactory(getState());
+    const loadingMessage = getLoadingMessage();
+
     const title = {
       onceQueryIsRun: loadingMessage,
       ifQueryTakesLong: t`Still Here...`,
diff --git a/frontend/src/metabase/query_builder/components/QueryVisualization.jsx b/frontend/src/metabase/query_builder/components/QueryVisualization.jsx
index 11fc11c62f10213a4fa116828b60e59eb853a5c4..30564718cd24a3da4fd9d9852c788e737ad79d90 100644
--- a/frontend/src/metabase/query_builder/components/QueryVisualization.jsx
+++ b/frontend/src/metabase/query_builder/components/QueryVisualization.jsx
@@ -6,7 +6,7 @@ import { t } from "ttag";
 
 import LoadingSpinner from "metabase/components/LoadingSpinner";
 import { useSelector } from "metabase/lib/redux";
-import { getWhiteLabeledLoadingMessage } from "metabase/selectors/whitelabel";
+import { getWhiteLabeledLoadingMessageFactory } from "metabase/selectors/whitelabel";
 import { HARD_ROW_LIMIT } from "metabase-lib/queries/utils";
 
 import RunButtonWithTooltip from "./RunButtonWithTooltip";
@@ -82,11 +82,11 @@ export const VisualizationEmptyState = ({ className }) => (
 export function VisualizationRunningState({ className = "" }) {
   const [isSlow] = useTimeout(SLOW_MESSAGE_TIMEOUT);
 
-  const loadingMessage = useSelector(getWhiteLabeledLoadingMessage);
+  const getLoadingMessage = useSelector(getWhiteLabeledLoadingMessageFactory);
 
   // show the slower loading message only when the loadingMessage is
-  // not customised
-  const message = loadingMessage(isSlow());
+  // not customized
+  const message = getLoadingMessage(isSlow());
 
   return (
     <div
diff --git a/frontend/src/metabase/query_builder/components/QueryVisualization.unit.spec.tsx b/frontend/src/metabase/query_builder/components/QueryVisualization.unit.spec.tsx
index d4834a40c689293d2860c0e9a10ca8842c6b2a0c..b0eecc07a3a2c7db051f07505d546cf80ec86ce5 100644
--- a/frontend/src/metabase/query_builder/components/QueryVisualization.unit.spec.tsx
+++ b/frontend/src/metabase/query_builder/components/QueryVisualization.unit.spec.tsx
@@ -10,7 +10,7 @@ type SetupOpts = {
 function setup({ customMessage }: SetupOpts = {}) {
   if (customMessage) {
     jest
-      .spyOn(PLUGIN_SELECTORS, "getLoadingMessage")
+      .spyOn(PLUGIN_SELECTORS, "getLoadingMessageFactory")
       .mockImplementation(() => customMessage);
   }
 
diff --git a/frontend/src/metabase/selectors/whitelabel/index.ts b/frontend/src/metabase/selectors/whitelabel/index.ts
index b162607788468c5fb0b954d9f069002be25e9b0a..66786e4394a64c34a711299ab5dc75feafd36eeb 100644
--- a/frontend/src/metabase/selectors/whitelabel/index.ts
+++ b/frontend/src/metabase/selectors/whitelabel/index.ts
@@ -1,8 +1,8 @@
 import { PLUGIN_SELECTORS } from "metabase/plugins";
 import type { State } from "metabase-types/store";
 
-export function getWhiteLabeledLoadingMessage(state: State) {
-  return PLUGIN_SELECTORS.getLoadingMessage(state);
+export function getWhiteLabeledLoadingMessageFactory(state: State) {
+  return PLUGIN_SELECTORS.getLoadingMessageFactory(state);
 }
 
 export function getIsWhiteLabeling(state: State) {
diff --git a/frontend/src/metabase/selectors/whitelabel/tests/common.unit.spec.ts b/frontend/src/metabase/selectors/whitelabel/tests/common.unit.spec.ts
index 5b72bb1a5d1a912851ef3afe341053f6c7c7a394..6e95a37bb22ae9ec718f09dd68607f1972795f64 100644
--- a/frontend/src/metabase/selectors/whitelabel/tests/common.unit.spec.ts
+++ b/frontend/src/metabase/selectors/whitelabel/tests/common.unit.spec.ts
@@ -2,7 +2,7 @@ import {
   getApplicationName,
   getIsWhiteLabeling,
   getShowMetabaseLinks,
-  getWhiteLabeledLoadingMessage,
+  getWhiteLabeledLoadingMessageFactory,
   getCanWhitelabel,
 } from "..";
 
@@ -12,10 +12,10 @@ describe("getWhiteLabeledLoadingMessage (OSS)", () => {
   it("should return 'Doing science...' when loading-message is set to 'doing-science'", () => {
     const { getState } = setup({ loadingMessage: "doing-science" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Doing science...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Waiting for results...",
     );
   });
@@ -23,10 +23,10 @@ describe("getWhiteLabeledLoadingMessage (OSS)", () => {
   it("should return 'Doing science...' when loading-message is set to 'loading-results'", () => {
     const { getState } = setup({ loadingMessage: "loading-results" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Doing science...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Waiting for results...",
     );
   });
@@ -34,10 +34,10 @@ describe("getWhiteLabeledLoadingMessage (OSS)", () => {
   it("should return 'Doing science...' when loading-message is set to 'running-query'", () => {
     const { getState } = setup({ loadingMessage: "running-query" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Doing science...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Waiting for results...",
     );
   });
diff --git a/frontend/src/metabase/selectors/whitelabel/tests/enterprise.unit.spec.ts b/frontend/src/metabase/selectors/whitelabel/tests/enterprise.unit.spec.ts
index 32c8a42486b23fdb5d5e14acc025a5d8f39e7e5e..861df1d48e114ecc268269ebc39151d859e5d1fa 100644
--- a/frontend/src/metabase/selectors/whitelabel/tests/enterprise.unit.spec.ts
+++ b/frontend/src/metabase/selectors/whitelabel/tests/enterprise.unit.spec.ts
@@ -3,7 +3,7 @@ import {
   getCanWhitelabel,
   getIsWhiteLabeling,
   getShowMetabaseLinks,
-  getWhiteLabeledLoadingMessage,
+  getWhiteLabeledLoadingMessageFactory,
 } from "..";
 
 import type { SetupOpts } from "./setup";
@@ -17,10 +17,10 @@ describe("getWhiteLabeledLoadingMessage (EE without token)", () => {
   it("should return 'Doing science...' when loading-message is set to 'doing-science'", () => {
     const { getState } = setup({ loadingMessage: "doing-science" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Doing science...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Waiting for results...",
     );
   });
@@ -28,10 +28,10 @@ describe("getWhiteLabeledLoadingMessage (EE without token)", () => {
   it("should return 'Doing science...' when loading-message is set to 'loading-results'", () => {
     const { getState } = setup({ loadingMessage: "loading-results" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Doing science...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Waiting for results...",
     );
   });
@@ -39,10 +39,10 @@ describe("getWhiteLabeledLoadingMessage (EE without token)", () => {
   it("should return 'Doing science...' when loading-message is set to 'running-query'", () => {
     const { getState } = setup({ loadingMessage: "running-query" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Doing science...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Waiting for results...",
     );
   });
diff --git a/frontend/src/metabase/selectors/whitelabel/tests/premium.unit.spec.ts b/frontend/src/metabase/selectors/whitelabel/tests/premium.unit.spec.ts
index 7b8fbb663c1b60c58f21d681718eb250e57d71bb..ec95caf1afc30c2b23a88b3c423a09210394c450 100644
--- a/frontend/src/metabase/selectors/whitelabel/tests/premium.unit.spec.ts
+++ b/frontend/src/metabase/selectors/whitelabel/tests/premium.unit.spec.ts
@@ -3,7 +3,7 @@ import {
   getCanWhitelabel,
   getIsWhiteLabeling,
   getShowMetabaseLinks,
-  getWhiteLabeledLoadingMessage,
+  getWhiteLabeledLoadingMessageFactory,
 } from "..";
 
 import type { SetupOpts } from "./setup";
@@ -21,10 +21,10 @@ describe("getWhiteLabeledLoadingMessage (EE with token)", () => {
   it("should return 'Doing science...' when loading-message is set to 'doing-science'", () => {
     const { getState } = setup({ loadingMessage: "doing-science" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Doing science...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Waiting for results...",
     );
   });
@@ -32,10 +32,10 @@ describe("getWhiteLabeledLoadingMessage (EE with token)", () => {
   it("should return 'Loading results...' when loading-message is set to 'loading-results'", () => {
     const { getState } = setup({ loadingMessage: "loading-results" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Loading results...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Loading results...",
     );
   });
@@ -43,10 +43,10 @@ describe("getWhiteLabeledLoadingMessage (EE with token)", () => {
   it("should return 'Running query...' when loading-message is set to 'running-query'", () => {
     const { getState } = setup({ loadingMessage: "running-query" });
 
-    expect(getWhiteLabeledLoadingMessage(getState())(false)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(false)).toBe(
       "Running query...",
     );
-    expect(getWhiteLabeledLoadingMessage(getState())(true)).toBe(
+    expect(getWhiteLabeledLoadingMessageFactory(getState())(true)).toBe(
       "Running query...",
     );
   });