diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml
index 43969bbb70322511a52d9329f9a0e9ebdde4b671..e23b80d2b8f67fe1960a9af51de5da2231e5a205 100644
--- a/docs/sample_config.yaml
+++ b/docs/sample_config.yaml
@@ -306,6 +306,11 @@ listeners:
 #
 #allow_per_room_profiles: false
 
+# How long to keep redacted events in unredacted form in the database.
+# By default redactions are kept indefinitely.
+#
+#redaction_retention_period: 30d
+
 
 ## TLS ##
 
diff --git a/synapse/config/server.py b/synapse/config/server.py
index 2abdef0971a69f84522d7dcc848878664a2e84e9..8efab924d4241916111d7016824cb92717817ab3 100644
--- a/synapse/config/server.py
+++ b/synapse/config/server.py
@@ -162,6 +162,16 @@ class ServerConfig(Config):
 
         self.mau_trial_days = config.get("mau_trial_days", 0)
 
+        # How long to keep redacted events in the database in unredacted form
+        # before redacting them.
+        redaction_retention_period = config.get("redaction_retention_period")
+        if redaction_retention_period:
+            self.redaction_retention_period = self.parse_duration(
+                redaction_retention_period
+            )
+        else:
+            self.redaction_retention_period = None
+
         # Options to disable HS
         self.hs_disabled = config.get("hs_disabled", False)
         self.hs_disabled_message = config.get("hs_disabled_message", "")
@@ -718,6 +728,11 @@ class ServerConfig(Config):
         # Defaults to 'true'.
         #
         #allow_per_room_profiles: false
+
+        # How long to keep redacted events in unredacted form in the database.
+        # By default redactions are kept indefinitely.
+        #
+        #redaction_retention_period: 30d
         """
             % locals()
         )
diff --git a/synapse/storage/events.py b/synapse/storage/events.py
index 2970da6829afe83890caeaf9351ab9eb054c268a..d0d1781c9012762913f638aa9cf8a0bb136c4422 100644
--- a/synapse/storage/events.py
+++ b/synapse/storage/events.py
@@ -1566,10 +1566,12 @@ class EventsStore(
             Deferred
         """
 
-        if self.stream_ordering_month_ago is None:
+        if not self.hs.config.redaction_retention_period:
             return
 
-        max_pos = self.stream_ordering_month_ago
+        max_pos = yield self.find_first_stream_ordering_after_ts(
+            self._clock.time_msec() - self.hs.config.redaction_retention_period
+        )
 
         # We fetch all redactions that point to an event that we have that has
         # a stream ordering from over a month ago, that we haven't yet censored
diff --git a/tests/storage/test_redaction.py b/tests/storage/test_redaction.py
index 0c9f3c70710aea2e6a95c60b07c2f94ab7fd2842..f0e86d41a8c90087b5ebb21ca04238e79119593d 100644
--- a/tests/storage/test_redaction.py
+++ b/tests/storage/test_redaction.py
@@ -344,7 +344,9 @@ class RedactionTestCase(unittest.HomeserverTestCase):
             {"content": {"body": "t", "msgtype": "message"}}, json.loads(event_json)
         )
 
-        # Advance by 30 days
+        # Advance by 30 days, then advance again to ensure that the looping call
+        # for updating the stream position gets called and then the looping call
+        # for the censoring gets called.
         self.reactor.advance(60 * 60 * 24 * 31)
         self.reactor.advance(60 * 60 * 2)