diff --git a/homeassistant/components/bmw_connected_drive/config_flow.py b/homeassistant/components/bmw_connected_drive/config_flow.py
index 4f05794e311..0cde37ba6b3 100644
--- a/homeassistant/components/bmw_connected_drive/config_flow.py
+++ b/homeassistant/components/bmw_connected_drive/config_flow.py
@@ -1,6 +1,7 @@
 """Config flow for BMW ConnectedDrive integration."""
 from __future__ import annotations
 
+from collections.abc import Mapping
 from typing import Any
 
 from bimmer_connected.api.authentication import MyBMWAuthentication
@@ -55,36 +56,61 @@ class BMWConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
 
     VERSION = 1
 
+    _reauth_entry: config_entries.ConfigEntry | None = None
+
     async def async_step_user(
         self, user_input: dict[str, Any] | None = None
     ) -> FlowResult:
         """Handle the initial step."""
         errors: dict[str, str] = {}
+
         if user_input is not None:
             unique_id = f"{user_input[CONF_REGION]}-{user_input[CONF_USERNAME]}"
 
-            await self.async_set_unique_id(unique_id)
-            self._abort_if_unique_id_configured()
+            if not self._reauth_entry:
+                await self.async_set_unique_id(unique_id)
+                self._abort_if_unique_id_configured()
 
             info = None
             try:
                 info = await validate_input(self.hass, user_input)
+                entry_data = {
+                    **user_input,
+                    CONF_REFRESH_TOKEN: info.get(CONF_REFRESH_TOKEN),
+                }
             except CannotConnect:
                 errors["base"] = "cannot_connect"
 
             if info:
+                if self._reauth_entry:
+                    self.hass.config_entries.async_update_entry(
+                        self._reauth_entry, data=entry_data
+                    )
+                    self.hass.async_create_task(
+                        self.hass.config_entries.async_reload(
+                            self._reauth_entry.entry_id
+                        )
+                    )
+                    return self.async_abort(reason="reauth_successful")
+
                 return self.async_create_entry(
                     title=info["title"],
-                    data={
-                        **user_input,
-                        CONF_REFRESH_TOKEN: info.get(CONF_REFRESH_TOKEN),
-                    },
+                    data=entry_data,
                 )
 
-        return self.async_show_form(
-            step_id="user", data_schema=DATA_SCHEMA, errors=errors
+        schema = self.add_suggested_values_to_schema(
+            DATA_SCHEMA, self._reauth_entry.data if self._reauth_entry else {}
         )
 
+        return self.async_show_form(step_id="user", data_schema=schema, errors=errors)
+
+    async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult:
+        """Handle configuration by re-auth."""
+        self._reauth_entry = self.hass.config_entries.async_get_entry(
+            self.context["entry_id"]
+        )
+        return await self.async_step_user()
+
     @staticmethod
     @callback
     def async_get_options_flow(
diff --git a/homeassistant/components/bmw_connected_drive/coordinator.py b/homeassistant/components/bmw_connected_drive/coordinator.py
index 0f03505ff29..ae139d4c64a 100644
--- a/homeassistant/components/bmw_connected_drive/coordinator.py
+++ b/homeassistant/components/bmw_connected_drive/coordinator.py
@@ -12,6 +12,7 @@ from httpx import HTTPError, HTTPStatusError, TimeoutException
 from homeassistant.config_entries import ConfigEntry
 from homeassistant.const import CONF_PASSWORD, CONF_REGION, CONF_USERNAME
 from homeassistant.core import HomeAssistant
+from homeassistant.exceptions import ConfigEntryAuthFailed
 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
 
 from .const import CONF_READ_ONLY, CONF_REFRESH_TOKEN, DOMAIN
@@ -65,8 +66,9 @@ class BMWDataUpdateCoordinator(DataUpdateCoordinator[None]):
                 401,
                 403,
             ):
-                # Clear refresh token only on issues with authorization
+                # Clear refresh token only and trigger reauth
                 self._update_config_entry_refresh_token(None)
+                raise ConfigEntryAuthFailed(str(err)) from err
             raise UpdateFailed(f"Error communicating with BMW API: {err}") from err
 
         if self.account.refresh_token != old_refresh_token:
diff --git a/homeassistant/components/bmw_connected_drive/strings.json b/homeassistant/components/bmw_connected_drive/strings.json
index 3e93cccb8c6..506175becd9 100644
--- a/homeassistant/components/bmw_connected_drive/strings.json
+++ b/homeassistant/components/bmw_connected_drive/strings.json
@@ -14,7 +14,8 @@
       "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
     },
     "abort": {
-      "already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
+      "already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
+      "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
     }
   },
   "options": {
diff --git a/tests/components/bmw_connected_drive/test_config_flow.py b/tests/components/bmw_connected_drive/test_config_flow.py
index e441be88263..4db57ad3022 100644
--- a/tests/components/bmw_connected_drive/test_config_flow.py
+++ b/tests/components/bmw_connected_drive/test_config_flow.py
@@ -1,4 +1,5 @@
 """Test the for the BMW Connected Drive config flow."""
+from copy import deepcopy
 from unittest.mock import patch
 
 from bimmer_connected.api.authentication import MyBMWAuthentication
@@ -10,7 +11,7 @@ from homeassistant.components.bmw_connected_drive.const import (
     CONF_READ_ONLY,
     CONF_REFRESH_TOKEN,
 )
-from homeassistant.const import CONF_USERNAME
+from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
 from homeassistant.core import HomeAssistant
 
 from . import FIXTURE_CONFIG_ENTRY, FIXTURE_REFRESH_TOKEN, FIXTURE_USER_INPUT
@@ -110,3 +111,51 @@ async def test_options_flow_implementation(hass: HomeAssistant) -> None:
         }
 
         assert len(mock_setup_entry.mock_calls) == 1
+
+
+async def test_reauth(hass: HomeAssistant) -> None:
+    """Test the reauth form."""
+    with patch(
+        "bimmer_connected.api.authentication.MyBMWAuthentication.login",
+        side_effect=login_sideeffect,
+        autospec=True,
+    ), patch(
+        "homeassistant.components.bmw_connected_drive.async_setup_entry",
+        return_value=True,
+    ) as mock_setup_entry:
+        wrong_password = "wrong"
+
+        config_entry_with_wrong_password = deepcopy(FIXTURE_CONFIG_ENTRY)
+        config_entry_with_wrong_password["data"][CONF_PASSWORD] = wrong_password
+
+        config_entry = MockConfigEntry(**config_entry_with_wrong_password)
+        config_entry.add_to_hass(hass)
+
+        await hass.config_entries.async_setup(config_entry.entry_id)
+        await hass.async_block_till_done()
+
+        assert config_entry.data == config_entry_with_wrong_password["data"]
+
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN,
+            context={
+                "source": config_entries.SOURCE_REAUTH,
+                "unique_id": config_entry.unique_id,
+                "entry_id": config_entry.entry_id,
+            },
+        )
+
+        assert result["type"] == data_entry_flow.FlowResultType.FORM
+        assert result["step_id"] == "user"
+        assert result["errors"] == {}
+
+        result2 = await hass.config_entries.flow.async_configure(
+            result["flow_id"], FIXTURE_USER_INPUT
+        )
+        await hass.async_block_till_done()
+
+        assert result2["type"] == data_entry_flow.FlowResultType.ABORT
+        assert result2["reason"] == "reauth_successful"
+        assert config_entry.data == FIXTURE_COMPLETE_ENTRY
+
+        assert len(mock_setup_entry.mock_calls) == 1