diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py
index 22f8f0f261d..12d928e172a 100644
--- a/homeassistant/components/zha/core/const.py
+++ b/homeassistant/components/zha/core/const.py
@@ -155,6 +155,9 @@ DEBUG_RELAY_LOGGERS = [DEBUG_COMP_ZHA, DEBUG_COMP_ZIGPY]
 DEFAULT_RADIO_TYPE = "ezsp"
 DEFAULT_BAUDRATE = 57600
 DEFAULT_DATABASE_NAME = "zigbee.db"
+
+DEVICE_PAIRING_STATUS = "pairing_status"
+
 DISCOVERY_KEY = "zha_discovery_info"
 
 DOMAIN = "zha"
diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py
index 13a87c13226..bec429cdf22 100644
--- a/homeassistant/components/zha/core/gateway.py
+++ b/homeassistant/components/zha/core/gateway.py
@@ -3,6 +3,7 @@
 import asyncio
 import collections
 from datetime import timedelta
+from enum import Enum
 import itertools
 import logging
 import os
@@ -54,6 +55,7 @@ from .const import (
     DEBUG_LEVELS,
     DEBUG_RELAY_LOGGERS,
     DEFAULT_DATABASE_NAME,
+    DEVICE_PAIRING_STATUS,
     DOMAIN,
     SIGNAL_ADD_ENTITIES,
     SIGNAL_GROUP_MEMBERSHIP_CHANGE,
@@ -94,6 +96,15 @@ EntityReference = collections.namedtuple(
 )
 
 
+class DevicePairingStatus(Enum):
+    """Status of a device."""
+
+    PAIRED = 1
+    INTERVIEW_COMPLETE = 2
+    CONFIGURED = 3
+    INITIALIZED = 4
+
+
 class ZHAGateway:
     """Gateway that handles events that happen on the ZHA Zigbee network."""
 
@@ -240,8 +251,11 @@ class ZHAGateway:
             ZHA_GW_MSG,
             {
                 ATTR_TYPE: ZHA_GW_MSG_DEVICE_JOINED,
-                ATTR_NWK: device.nwk,
-                ATTR_IEEE: str(device.ieee),
+                ZHA_GW_MSG_DEVICE_INFO: {
+                    ATTR_NWK: device.nwk,
+                    ATTR_IEEE: str(device.ieee),
+                    DEVICE_PAIRING_STATUS: DevicePairingStatus.PAIRED.name,
+                },
             },
         )
 
@@ -253,11 +267,14 @@ class ZHAGateway:
             ZHA_GW_MSG,
             {
                 ATTR_TYPE: ZHA_GW_MSG_RAW_INIT,
-                ATTR_NWK: device.nwk,
-                ATTR_IEEE: str(device.ieee),
-                ATTR_MODEL: device.model if device.model else UNKNOWN_MODEL,
-                ATTR_MANUFACTURER: manuf if manuf else UNKNOWN_MANUFACTURER,
-                ATTR_SIGNATURE: device.get_signature(),
+                ZHA_GW_MSG_DEVICE_INFO: {
+                    ATTR_NWK: device.nwk,
+                    ATTR_IEEE: str(device.ieee),
+                    DEVICE_PAIRING_STATUS: DevicePairingStatus.INTERVIEW_COMPLETE.name,
+                    ATTR_MODEL: device.model if device.model else UNKNOWN_MODEL,
+                    ATTR_MANUFACTURER: manuf if manuf else UNKNOWN_MANUFACTURER,
+                    ATTR_SIGNATURE: device.get_signature(),
+                },
             },
         )
 
@@ -552,8 +569,8 @@ class ZHAGateway:
             )
             await self._async_device_joined(zha_device)
 
-        device_info = zha_device.zha_device_info
-
+        device_info = zha_device.device_info
+        device_info[DEVICE_PAIRING_STATUS] = DevicePairingStatus.INITIALIZED.name
         async_dispatcher_send(
             self._hass,
             ZHA_GW_MSG,
@@ -565,7 +582,17 @@ class ZHAGateway:
 
     async def _async_device_joined(self, zha_device: zha_typing.ZhaDeviceType) -> None:
         zha_device.available = True
+        device_info = zha_device.device_info
         await zha_device.async_configure()
+        device_info[DEVICE_PAIRING_STATUS] = DevicePairingStatus.CONFIGURED.name
+        async_dispatcher_send(
+            self._hass,
+            ZHA_GW_MSG,
+            {
+                ATTR_TYPE: ZHA_GW_MSG_DEVICE_FULL_INIT,
+                ZHA_GW_MSG_DEVICE_INFO: device_info,
+            },
+        )
         await zha_device.async_initialize(from_cache=False)
         async_dispatcher_send(self._hass, SIGNAL_ADD_ENTITIES)
 
@@ -577,6 +604,16 @@ class ZHAGateway:
         )
         # we don't have to do this on a nwk swap but we don't have a way to tell currently
         await zha_device.async_configure()
+        device_info = zha_device.device_info
+        device_info[DEVICE_PAIRING_STATUS] = DevicePairingStatus.CONFIGURED.name
+        async_dispatcher_send(
+            self._hass,
+            ZHA_GW_MSG,
+            {
+                ATTR_TYPE: ZHA_GW_MSG_DEVICE_FULL_INIT,
+                ZHA_GW_MSG_DEVICE_INFO: device_info,
+            },
+        )
         # force async_initialize() to fire so don't explicitly call it
         zha_device.available = False
         zha_device.update_available(True)