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
@@ -666,8 +666,10 @@
     &self,
     user_id: String,
   ) -> Result<DeleteItemOutput, Error> {
-    debug!("Attempting to delete user: {}", user_id);
+    debug!(user_id, "Attempting to delete user's devices");
+    self.delete_devices_table_rows_for_user(&user_id).await?;
 
+    debug!(user_id, "Attempting to delete user");
     match self
       .client
       .delete_item()
diff --git a/services/identity/src/database/device_list.rs b/services/identity/src/database/device_list.rs
--- a/services/identity/src/database/device_list.rs
+++ b/services/identity/src/database/device_list.rs
@@ -6,7 +6,9 @@
 use aws_sdk_dynamodb::{
   client::fluent_builders::Query,
   error::TransactionCanceledException,
-  model::{AttributeValue, Put, TransactWriteItem, Update},
+  model::{
+    AttributeValue, DeleteRequest, Put, TransactWriteItem, Update, WriteRequest,
+  },
   output::GetItemOutput,
 };
 use chrono::{DateTime, Utc};
@@ -594,6 +596,62 @@
 
     Ok(())
   }
+
+  /// Deletes all user data from devices table
+  pub async fn delete_devices_table_rows_for_user(
+    &self,
+    user_id: impl Into<String>,
+  ) -> Result<(), Error> {
+    // 1. get all rows
+    // 2. batch write delete all
+
+    // we project only the primary keys so we can pass these directly to delete requests
+    let primary_keys = self
+      .client
+      .query()
+      .table_name(devices_table::NAME)
+      .projection_expression("#user_id, #item_id")
+      .key_condition_expression("#user_id = :user_id")
+      .expression_attribute_names("#user_id", ATTR_USER_ID)
+      .expression_attribute_names("#item_id", ATTR_ITEM_ID)
+      .expression_attribute_values(
+        ":user_id",
+        AttributeValue::S(user_id.into()),
+      )
+      .consistent_read(true)
+      .send()
+      .await
+      .map_err(|e| {
+        error!("Failed to list user's items in devices table: {:?}", e);
+        Error::AwsSdk(e.into())
+      })?
+      .items
+      .unwrap_or_default();
+
+    let delete_requests = primary_keys
+      .into_iter()
+      .map(|item| {
+        let request = DeleteRequest::builder().set_key(Some(item)).build();
+        WriteRequest::builder().delete_request(request).build()
+      })
+      .collect::<Vec<_>>();
+
+    // TODO: We can use the batch write helper from comm-services-lib when integrated
+    for batch in delete_requests.chunks(25) {
+      self
+        .client
+        .batch_write_item()
+        .request_items(devices_table::NAME, batch.to_vec())
+        .send()
+        .await
+        .map_err(|e| {
+          error!("Failed to batch delete items from devices table: {:?}", e);
+          Error::AwsSdk(e.into())
+        })?;
+    }
+
+    Ok(())
+  }
 }
 
 /// Gets timestamp of user's current device list. Returns None if the user