diff --git a/homeassistant/components/zha/config_flow.py b/homeassistant/components/zha/config_flow.py
index 2d8443642e7..b94b620581e 100644
--- a/homeassistant/components/zha/config_flow.py
+++ b/homeassistant/components/zha/config_flow.py
@@ -102,14 +102,17 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
         device = discovery_info["device"]
         manufacturer = discovery_info["manufacturer"]
         description = discovery_info["description"]
-        await self.async_set_unique_id(
-            f"{vid}:{pid}_{serial_number}_{manufacturer}_{description}"
-        )
-        self._abort_if_unique_id_configured(
-            updates={
-                CONF_DEVICE: {CONF_DEVICE_PATH: self._device_path},
-            }
-        )
+        dev_path = await self.hass.async_add_executor_job(usb.get_serial_by_id, device)
+        unique_id = f"{vid}:{pid}_{serial_number}_{manufacturer}_{description}"
+        if current_entry := await self.async_set_unique_id(unique_id):
+            self._abort_if_unique_id_configured(
+                updates={
+                    CONF_DEVICE: {
+                        **current_entry.data[CONF_DEVICE],
+                        CONF_DEVICE_PATH: dev_path,
+                    },
+                }
+            )
         # Check if already configured
         if self._async_current_entries():
             return self.async_abort(reason="single_instance_allowed")
@@ -127,7 +130,6 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
         if vid == "10C4" and pid == "8A2A" and "ZigBee" not in description:
             return self.async_abort(reason="not_zha_device")
 
-        dev_path = await self.hass.async_add_executor_job(usb.get_serial_by_id, device)
         self._auto_detected_data = await detect_radios(dev_path)
         if self._auto_detected_data is None:
             return self.async_abort(reason="not_zha_device")
@@ -166,12 +168,15 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
         host = discovery_info[CONF_HOST]
         device_path = f"socket://{host}:6638"
 
-        await self.async_set_unique_id(node_name)
-        self._abort_if_unique_id_configured(
-            updates={
-                CONF_DEVICE: {CONF_DEVICE_PATH: device_path},
-            }
-        )
+        if current_entry := await self.async_set_unique_id(node_name):
+            self._abort_if_unique_id_configured(
+                updates={
+                    CONF_DEVICE: {
+                        **current_entry.data[CONF_DEVICE],
+                        CONF_DEVICE_PATH: device_path,
+                    },
+                }
+            )
 
         # Check if already configured
         if self._async_current_entries():
diff --git a/tests/components/zha/test_config_flow.py b/tests/components/zha/test_config_flow.py
index ed975f77eae..81957f010dd 100644
--- a/tests/components/zha/test_config_flow.py
+++ b/tests/components/zha/test_config_flow.py
@@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
 import pytest
 import serial.tools.list_ports
 import zigpy.config
+from zigpy.config import CONF_DEVICE, CONF_DEVICE_PATH
 
 from homeassistant import setup
 from homeassistant.components.ssdp import (
@@ -13,7 +14,13 @@ from homeassistant.components.ssdp import (
     ATTR_UPNP_SERIAL,
 )
 from homeassistant.components.zha import config_flow
-from homeassistant.components.zha.core.const import CONF_RADIO_TYPE, DOMAIN, RadioType
+from homeassistant.components.zha.core.const import (
+    CONF_BAUDRATE,
+    CONF_FLOWCONTROL,
+    CONF_RADIO_TYPE,
+    DOMAIN,
+    RadioType,
+)
 from homeassistant.config_entries import (
     SOURCE_SSDP,
     SOURCE_USB,
@@ -21,7 +28,11 @@ from homeassistant.config_entries import (
     SOURCE_ZEROCONF,
 )
 from homeassistant.const import CONF_SOURCE
-from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM
+from homeassistant.data_entry_flow import (
+    RESULT_TYPE_ABORT,
+    RESULT_TYPE_CREATE_ENTRY,
+    RESULT_TYPE_FORM,
+)
 
 from tests.common import MockConfigEntry
 
@@ -57,15 +68,51 @@ async def test_discovery(detect_mock, hass):
     assert result["type"] == RESULT_TYPE_CREATE_ENTRY
     assert result["title"] == "socket://192.168.1.200:6638"
     assert result["data"] == {
-        "device": {
-            "baudrate": 115200,
-            "flow_control": None,
-            "path": "socket://192.168.1.200:6638",
+        CONF_DEVICE: {
+            CONF_BAUDRATE: 115200,
+            CONF_FLOWCONTROL: None,
+            CONF_DEVICE_PATH: "socket://192.168.1.200:6638",
         },
         CONF_RADIO_TYPE: "znp",
     }
 
 
+@patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True))
+@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
+async def test_discovery_via_zeroconf_ip_change(detect_mock, hass):
+    """Test zeroconf flow -- radio detected."""
+    entry = MockConfigEntry(
+        domain=DOMAIN,
+        unique_id="tube_zb_gw_cc2652p2_poe",
+        data={
+            CONF_DEVICE: {
+                CONF_DEVICE_PATH: "socket://192.168.1.5:6638",
+                CONF_BAUDRATE: 115200,
+                CONF_FLOWCONTROL: None,
+            }
+        },
+    )
+    entry.add_to_hass(hass)
+
+    service_info = {
+        "host": "192.168.1.22",
+        "port": 6053,
+        "hostname": "tube_zb_gw_cc2652p2_poe.local.",
+        "properties": {"address": "tube_zb_gw_cc2652p2_poe.local"},
+    }
+    result = await hass.config_entries.flow.async_init(
+        "zha", context={"source": SOURCE_ZEROCONF}, data=service_info
+    )
+
+    assert result["type"] == RESULT_TYPE_ABORT
+    assert result["reason"] == "already_configured"
+    assert entry.data[CONF_DEVICE] == {
+        CONF_DEVICE_PATH: "socket://192.168.1.22:6638",
+        CONF_BAUDRATE: 115200,
+        CONF_FLOWCONTROL: None,
+    }
+
+
 @patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
 async def test_discovery_via_usb(detect_mock, hass):
     """Test usb flow -- radio detected."""
@@ -117,7 +164,7 @@ async def test_discovery_via_usb_no_radio(detect_mock, hass):
         "zha", context={"source": SOURCE_USB}, data=discovery_info
     )
     await hass.async_block_till_done()
-    assert result["type"] == "abort"
+    assert result["type"] == RESULT_TYPE_ABORT
     assert result["reason"] == "not_zha_device"
 
 
@@ -136,7 +183,7 @@ async def test_discovery_via_usb_rejects_nortek_zwave(detect_mock, hass):
         "zha", context={"source": SOURCE_USB}, data=discovery_info
     )
     await hass.async_block_till_done()
-    assert result["type"] == "abort"
+    assert result["type"] == RESULT_TYPE_ABORT
     assert result["reason"] == "not_zha_device"
 
 
@@ -144,7 +191,9 @@ async def test_discovery_via_usb_rejects_nortek_zwave(detect_mock, hass):
 async def test_discovery_via_usb_already_setup(detect_mock, hass):
     """Test usb flow -- already setup."""
     await setup.async_setup_component(hass, "persistent_notification", {})
-    MockConfigEntry(domain=DOMAIN, data={"usb_path": "/dev/ttyUSB1"}).add_to_hass(hass)
+    MockConfigEntry(
+        domain=DOMAIN, data={CONF_DEVICE: {CONF_DEVICE_PATH: "/dev/ttyUSB1"}}
+    ).add_to_hass(hass)
 
     discovery_info = {
         "device": "/dev/ttyZIGBEE",
@@ -159,10 +208,49 @@ async def test_discovery_via_usb_already_setup(detect_mock, hass):
     )
     await hass.async_block_till_done()
 
-    assert result["type"] == "abort"
+    assert result["type"] == RESULT_TYPE_ABORT
     assert result["reason"] == "single_instance_allowed"
 
 
+@patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True))
+async def test_discovery_via_usb_path_changes(hass):
+    """Test usb flow already setup and the path changes."""
+    await setup.async_setup_component(hass, "persistent_notification", {})
+    entry = MockConfigEntry(
+        domain=DOMAIN,
+        unique_id="AAAA:AAAA_1234_test_zigbee radio",
+        data={
+            CONF_DEVICE: {
+                CONF_DEVICE_PATH: "/dev/ttyUSB1",
+                CONF_BAUDRATE: 115200,
+                CONF_FLOWCONTROL: None,
+            }
+        },
+    )
+    entry.add_to_hass(hass)
+
+    discovery_info = {
+        "device": "/dev/ttyZIGBEE",
+        "pid": "AAAA",
+        "vid": "AAAA",
+        "serial_number": "1234",
+        "description": "zigbee radio",
+        "manufacturer": "test",
+    }
+    result = await hass.config_entries.flow.async_init(
+        "zha", context={"source": SOURCE_USB}, data=discovery_info
+    )
+    await hass.async_block_till_done()
+
+    assert result["type"] == RESULT_TYPE_ABORT
+    assert result["reason"] == "already_configured"
+    assert entry.data[CONF_DEVICE] == {
+        CONF_DEVICE_PATH: "/dev/ttyZIGBEE",
+        CONF_BAUDRATE: 115200,
+        CONF_FLOWCONTROL: None,
+    }
+
+
 @patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
 async def test_discovery_via_usb_deconz_already_discovered(detect_mock, hass):
     """Test usb flow -- deconz discovered."""
@@ -204,7 +292,9 @@ async def test_discovery_already_setup(detect_mock, hass):
         "properties": {"name": "tube_123456"},
     }
     await setup.async_setup_component(hass, "persistent_notification", {})
-    MockConfigEntry(domain=DOMAIN, data={"usb_path": "/dev/ttyUSB1"}).add_to_hass(hass)
+    MockConfigEntry(
+        domain=DOMAIN, data={CONF_DEVICE: {CONF_DEVICE_PATH: "/dev/ttyUSB1"}}
+    ).add_to_hass(hass)
 
     result = await hass.config_entries.flow.async_init(
         "zha", context={"source": SOURCE_ZEROCONF}, data=service_info
@@ -310,7 +400,9 @@ async def test_pick_radio_flow(hass, radio_type):
 
 async def test_user_flow_existing_config_entry(hass):
     """Test if config entry already exists."""
-    MockConfigEntry(domain=DOMAIN, data={"usb_path": "/dev/ttyUSB1"}).add_to_hass(hass)
+    MockConfigEntry(
+        domain=DOMAIN, data={CONF_DEVICE: {CONF_DEVICE_PATH: "/dev/ttyUSB1"}}
+    ).add_to_hass(hass)
     await setup.async_setup_component(hass, "persistent_notification", {})
     result = await hass.config_entries.flow.async_init(
         DOMAIN, context={CONF_SOURCE: SOURCE_USER}