diff --git a/src/indexing/BaseEventIndexManager.js b/src/indexing/BaseEventIndexManager.js
index 66904f9264..f780c8e9ce 100644
--- a/src/indexing/BaseEventIndexManager.js
+++ b/src/indexing/BaseEventIndexManager.js
@@ -123,6 +123,10 @@ export default class BaseEventIndexManager {
         throw new Error("Unimplemented");
     }
 
+    async deleteEvent(eventId: string): Promise<boolean> {
+        throw new Error("Unimplemented");
+    }
+
     /**
      * Check if our event index is empty.
      */
diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js
index a9c27a254f..ddae1f2a53 100644
--- a/src/indexing/EventIndex.js
+++ b/src/indexing/EventIndex.js
@@ -61,6 +61,7 @@ export default class EventIndex extends EventEmitter {
         client.on('Room.timeline', this.onRoomTimeline);
         client.on('Event.decrypted', this.onEventDecrypted);
         client.on('Room.timelineReset', this.onTimelineReset);
+        client.on('Room.redaction', this.onRedaction);
     }
 
     /**
@@ -74,6 +75,7 @@ export default class EventIndex extends EventEmitter {
         client.removeListener('Room.timeline', this.onRoomTimeline);
         client.removeListener('Event.decrypted', this.onEventDecrypted);
         client.removeListener('Room.timelineReset', this.onTimelineReset);
+        client.removeListener('Room.redaction', this.onRedaction);
     }
 
     /**
@@ -210,6 +212,23 @@ export default class EventIndex extends EventEmitter {
         await this.addLiveEventToIndex(ev);
     }
 
+    /*
+     * The Room.redaction listener.
+     *
+     * Removes a redacted event from our event index.
+     */
+    onRedaction = async (ev, room) => {
+        // We only index encrypted rooms locally.
+        if (!MatrixClientPeg.get().isRoomEncrypted(room.roomId)) return;
+        const indexManager = PlatformPeg.get().getEventIndexingManager();
+
+        try {
+            await indexManager.deleteEvent(ev.getAssociatedId());
+        } catch (e) {
+            console.log("EventIndex: Error deleting event from index", e);
+        }
+    }
+
     /*
      * The Room.timelineReset listener.
      *
@@ -446,12 +465,17 @@ export default class EventIndex extends EventEmitter {
             // Let us wait for all the events to get decrypted.
             await Promise.all(decryptionPromises);
 
-
             // TODO if there are no events at this point we're missing a lot
             // decryption keys, do we want to retry this checkpoint at a later
             // stage?
             const filteredEvents = matrixEvents.filter(this.isValidEvent);
 
+            // Collect the redaction events so we can delete the redacted events
+            // from the index.
+            const redactionEvents = matrixEvents.filter((ev) => {
+                return ev.getType() === "m.room.redaction";
+            });
+
             // Let us convert the events back into a format that EventIndex can
             // consume.
             const events = filteredEvents.map((ev) => {
@@ -483,6 +507,11 @@ export default class EventIndex extends EventEmitter {
             );
 
             try {
+                for (let i = 0; i < redactionEvents.length; i++) {
+                    const ev = redactionEvents[i];
+                    await indexManager.deleteEvent(ev.getAssociatedId());
+                }
+
                 const eventsAlreadyAdded = await indexManager.addHistoricEvents(
                     events, newCheckpoint, checkpoint);
                 // If all events were already indexed we assume that we catched