diff --git a/services/identity/src/database.rs b/services/identity/src/database.rs
--- a/services/identity/src/database.rs
+++ b/services/identity/src/database.rs
@@ -532,11 +532,19 @@
     Ok(())
   }
 
+  /// Deletes all user data from DynamoDB. Returns device IDs
+  /// from user's device list.
   #[tracing::instrument(skip_all)]
   pub async fn delete_user(
     &self,
     user_id: String,
-  ) -> Result<DeleteItemOutput, Error> {
+  ) -> Result<Vec<String>, Error> {
+    let device_ids = self
+      .get_current_device_list(&user_id)
+      .await?
+      .map(|list| list.device_ids)
+      .unwrap_or_default();
+
     // We must delete the one-time keys first because doing so requires device
     // IDs from the devices table
     debug!(user_id, "Attempting to delete user's one-time keys");
@@ -571,7 +579,9 @@
         );
         Err(Error::AwsSdk(e.into()))
       }
-    }
+    }?;
+
+    Ok(device_ids)
   }
 
   pub async fn wallet_address_taken(
diff --git a/services/identity/src/grpc_services/authenticated.rs b/services/identity/src/grpc_services/authenticated.rs
--- a/services/identity/src/grpc_services/authenticated.rs
+++ b/services/identity/src/grpc_services/authenticated.rs
@@ -568,11 +568,12 @@
       ));
     }
 
-    self
+    let device_ids = self
       .db_client
       .delete_user(user_id)
       .await
       .map_err(handle_db_error)?;
+    spawn_delete_tunnelbroker_data_task(device_ids);
 
     let response = Empty {};
     Ok(Response::new(response))
@@ -654,11 +655,12 @@
       .finish(&message.opaque_login_upload)
       .map_err(protocol_error_to_grpc_status)?;
 
-    self
+    let device_ids = self
       .db_client
       .delete_user(user_id)
       .await
       .map_err(handle_db_error)?;
+    spawn_delete_tunnelbroker_data_task(device_ids);
 
     let response = Empty {};
     Ok(Response::new(response))