diff --git a/lib/handlers/db-ops-handler.react.js b/lib/handlers/db-ops-handler.react.js
--- a/lib/handlers/db-ops-handler.react.js
+++ b/lib/handlers/db-ops-handler.react.js
@@ -3,8 +3,14 @@
 import * as React from 'react';
 
 import { opsProcessingFinishedActionType } from '../actions/db-ops-actions.js';
+import { useTunnelbroker } from '../tunnelbroker/tunnelbroker-context.js';
 import type { DBOpsEntry } from '../types/db-ops-types.js';
 import type { StoreOperations } from '../types/store-ops-types.js';
+import {
+  type MessageProcessed,
+  peerToPeerMessageTypes,
+} from '../types/tunnelbroker/peer-to-peer-message-types.js';
+import { getConfig } from '../utils/config.js';
 import { useDispatch, useSelector } from '../utils/redux-utils.js';
 
 type Props = {
@@ -12,9 +18,11 @@
 };
 
 function DBOpsHandler(props: Props): React.Node {
+  const { sqliteAPI } = getConfig();
   const { processDBStoreOperations } = props;
   const queueFront = useSelector(state => state.dbOpsStore.queuedOps[0]);
   const prevQueueFront = React.useRef<?DBOpsEntry>(null);
+  const { sendMessage } = useTunnelbroker();
 
   const dispatch = useDispatch();
 
@@ -24,7 +32,7 @@
     }
     prevQueueFront.current = queueFront;
 
-    const ops = queueFront.ops;
+    const { ops, messageSourceMetadata } = queueFront;
     void (async () => {
       if (ops) {
         await processDBStoreOperations(ops);
@@ -32,8 +40,20 @@
       dispatch({
         type: opsProcessingFinishedActionType,
       });
+      if (messageSourceMetadata) {
+        const { messageID, senderDeviceID } = messageSourceMetadata;
+        const message: MessageProcessed = {
+          type: peerToPeerMessageTypes.MESSAGE_PROCESSED,
+          messageID,
+        };
+        await sendMessage({
+          deviceID: senderDeviceID,
+          payload: JSON.stringify(message),
+        });
+        await sqliteAPI.removeReceivedMessagesToDevice([messageID]);
+      }
     })();
-  }, [queueFront, dispatch, processDBStoreOperations]);
+  }, [queueFront, dispatch, processDBStoreOperations, sendMessage, sqliteAPI]);
 
   return null;
 }
diff --git a/lib/types/tunnelbroker/peer-to-peer-message-types.js b/lib/types/tunnelbroker/peer-to-peer-message-types.js
--- a/lib/types/tunnelbroker/peer-to-peer-message-types.js
+++ b/lib/types/tunnelbroker/peer-to-peer-message-types.js
@@ -25,6 +25,7 @@
   REFRESH_KEY_REQUEST: 'RefreshKeyRequest',
   QR_CODE_AUTH_MESSAGE: 'QRCodeAuthMessage',
   DEVICE_LIST_UPDATED: 'DeviceListUpdated',
+  MESSAGE_PROCESSED: 'MessageProcessed',
 });
 
 export type OutboundSessionCreation = {
@@ -87,12 +88,23 @@
     signedDeviceList: signedDeviceListValidator,
   });
 
+export type MessageProcessed = {
+  +type: 'MessageProcessed',
+  +messageID: string,
+};
+export const messageProcessedValidator: TInterface<MessageProcessed> =
+  tShape<MessageProcessed>({
+    type: tString(peerToPeerMessageTypes.MESSAGE_PROCESSED),
+    messageID: t.String,
+  });
+
 export type PeerToPeerMessage =
   | OutboundSessionCreation
   | EncryptedMessage
   | RefreshKeyRequest
   | QRCodeAuthMessage
-  | DeviceListUpdated;
+  | DeviceListUpdated
+  | MessageProcessed;
 
 export const peerToPeerMessageValidator: TUnion<PeerToPeerMessage> = t.union([
   outboundSessionCreationValidator,
@@ -100,4 +112,5 @@
   refreshKeysRequestValidator,
   qrCodeAuthMessageValidator,
   deviceListUpdatedValidator,
+  messageProcessedValidator,
 ]);