diff --git a/src/calng/CalibrationManager.py b/src/calng/CalibrationManager.py
index ab4eb34d8e1883a1e1987c49d706a7026d48b5c0..accc5ee5b360e4b2e50064507385d31ef32a06ef 100644
--- a/src/calng/CalibrationManager.py
+++ b/src/calng/CalibrationManager.py
@@ -465,14 +465,6 @@ class CalibrationManager(DeviceClientBase, Device):
         defaultValue=[],
         accessMode=AccessMode.READONLY)
 
-    @Slot(
-        displayedName='Discover managed devices',
-        description='',
-        allowedStates=[State.ACTIVE])
-    async def discoverManagedDevices(self):
-        self.state = State.CHANGING
-        background(self._discover_managed_devices())
-
     @Slot(
         displayedName='Apply managed values',
         description='Set all managed keys to the values currently active on '
@@ -581,7 +573,6 @@ class CalibrationManager(DeviceClientBase, Device):
         if info['type'] == 'device':
             self._check_new_device(instance_id, info['serverId'],
                                    info['classId'])
-            self._update_managed_devices()
 
     @slot
     def slotInstanceGone(self, instance_id, info):
@@ -590,12 +581,7 @@ class CalibrationManager(DeviceClientBase, Device):
         super().slotInstanceGone(instance_id, info)
 
         if info['type'] == 'device':
-            self._daq_device_ids.discard(instance_id)
-            self._domain_device_ids.discard(instance_id)
-            self._managed_device_ids.discard(instance_id)
-            self._correction_device_ids.discard(instance_id)
-            self._assembler_device_ids.discard(instance_id)
-            self._update_managed_devices()
+            self._remove_managed_device(instance_id)
 
     async def _async_init(self):
         # Set-up Tornado.
@@ -651,6 +637,16 @@ class CalibrationManager(DeviceClientBase, Device):
                 # This device is also an assembler
                 self._assembler_device_ids.add(device_id)
 
+            self._update_managed_devices()
+
+    def _remove_managed_device(self, device_id):
+        self._daq_device_ids.discard(device_id)
+        self._domain_device_ids.discard(device_id)
+        self._managed_device_ids.discard(device_id)
+        self._correction_device_ids.discard(device_id)
+        self._assembler_device_ids.discard(device_id)
+        self._update_managed_devices()
+
     async def _check_topology(self):
         for i in range(10):
             try:
@@ -673,34 +669,30 @@ class CalibrationManager(DeviceClientBase, Device):
             self._check_new_device(device_id, devices[device_id, 'serverId'],
                                    devices[device_id, 'classId'])
 
-        self._update_managed_devices(True)
-
-    async def _discover_managed_devices(self):
-        self._daq_device_ids.clear()
-        self._domain_device_ids.clear()
-        self._managed_device_ids.clear()
-        self._correction_device_ids.clear()
-        self._assembler_device_ids.clear()
+    async def _ping_managed_devices(self):
+        device_ids = sorted(self._managed_device_ids)
 
-        await self._check_topology()
+        device_infos = await gather(
+            *[wait_for(getInstanceInfo(device_id), timeout=5)
+              for device_id in device_ids],
+            return_exceptions=True)
 
-        self.state = State.ACTIVE
+        for device_id, device_info in zip(device_ids, device_infos):
+            if isinstance(device_info, AsyncTimeoutError):
+                self._remove_managed_device(device_id)
 
     async def _delayed_managed_devices_update(self):
         await sleep(1.0)  # Throttle updates to at most once a second.
         self.managedDevices = sorted(self._managed_device_ids)
         self._managed_devices_updater = None  # Clear task again.
 
-    def _update_managed_devices(self, forced=False):
+    def _update_managed_devices(self):
         if self._managed_devices_updater is not None:
             # Update already in progress, ignore.
             return
 
-        if forced or len(self._managed_device_ids) != len(self.managedDevices):
-            # Trigger an update either if forced or the number of
-            # devices changed.
-            self._managed_devices_updater = background(
-                self._delayed_managed_devices_update())
+        self._managed_devices_updater = background(
+            self._delayed_managed_devices_update())
 
     async def _get_shared_keys(self, device_ids, keys):
         """Find the most common property values on devices."""
@@ -1277,6 +1269,9 @@ class CalibrationManager(DeviceClientBase, Device):
                                    'listed in the device servers '
                                    'configuration')
 
+        # Ping all known managed devices to make sure they're alive.
+        await self._ping_managed_devices()
+
         # Instantiate modules.
         modules_by_group = defaultdict(list)
         correct_device_id_by_module = {}