diff --git a/danger/database/Dangerfile b/danger/database/Dangerfile
index 96134ea66a696727e2616e7f636911c403f76fa8..92d584c525e0cec1eea9adcef81d171a3e099f1f 100644
--- a/danger/database/Dangerfile
+++ b/danger/database/Dangerfile
@@ -35,6 +35,15 @@ DB_MIGRATION_TESTING_REQUIRED_MESSAGE = <<~MSG
    requesting review to test your migrations against production data.
 MSG
 
+DB_OLD_MIGRATIONS_MESSAGE = <<~MSG
+  ⌛ **Migration Timestamp Out of Date**
+  The following migrations have timestamps that are over three weeks old:
+
+  %<old_migrations>s
+
+  Please double check the timestamps and update them if possible. [Why does this matter?](https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-timestamp-age)
+MSG
+
 DATABASE_APPROVED_LABEL = 'database::approved'
 
 non_geo_db_schema_updated = !git.modified_files.grep(%r{\Adb/structure\.sql}).empty?
@@ -77,3 +86,11 @@ if helper.mr_labels.include?('database') || db_paths_to_review.any?
     helper.labels_to_add << 'database::review pending'
   end
 end
+
+cutoff = Date.today - 21 # Three weeks ago
+
+old_migrations = database.find_migration_files_before(git.added_files, cutoff)
+
+if old_migrations.present?
+  warn format(DB_OLD_MIGRATIONS_MESSAGE, old_migrations: old_migrations.map { |m| "* #{m}" }.join("\n"))
+end
diff --git a/danger/plugins/database.rb b/danger/plugins/database.rb
new file mode 100644
index 0000000000000000000000000000000000000000..77c0a484a594f1c3b500c2356e7fc7e532fee655
--- /dev/null
+++ b/danger/plugins/database.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/database'
+
+module Danger
+  class Database < ::Danger::Plugin
+    # Put the helper code somewhere it can be tested
+    include Tooling::Danger::Database
+  end
+end
diff --git a/spec/tooling/danger/database_spec.rb b/spec/tooling/danger/database_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ddcfa279dc3cf9959af8ef74e2b75d57c8a262cf
--- /dev/null
+++ b/spec/tooling/danger/database_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'gitlab-dangerfiles'
+require 'danger'
+require 'danger/plugins/internal/helper'
+require 'gitlab/dangerfiles/spec_helper'
+
+require_relative '../../../tooling/danger/database'
+
+RSpec.describe Tooling::Danger::Database, feature_category: :tooling do
+  include_context "with dangerfile"
+
+  let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+  let(:migration_files) do
+    [
+      # regular migrations
+      'db/migrate/20220901010203_add_widgets_table.rb',
+      'db/migrate/20220909010203_add_properties_column.rb',
+      'db/migrate/20220910010203_drop_tools_table.rb',
+      'db/migrate/20220912010203_add_index_to_widgets_table.rb',
+
+      # post migrations
+      'db/post_migrate/20220901010203_add_widgets_table.rb',
+      'db/post_migrate/20220909010203_add_properties_column.rb',
+      'db/post_migrate/20220910010203_drop_tools_table.rb',
+      'db/post_migrate/20220912010203_add_index_to_widgets_table.rb',
+
+      # ee migrations
+      'ee/db/migrate/20220901010203_add_widgets_table.rb',
+      'ee/db/migrate/20220909010203_add_properties_column.rb',
+      'ee/db/migrate/20220910010203_drop_tools_table.rb',
+      'ee/db/migrate/20220912010203_add_index_to_widgets_table.rb',
+
+      # geo migrations
+      'ee/db/geo/migrate/20220901010203_add_widgets_table.rb',
+      'ee/db/geo/migrate/20220909010203_add_properties_column.rb',
+      'ee/db/geo/migrate/20220910010203_drop_tools_table.rb',
+      'ee/db/geo/migrate/20220912010203_add_index_to_widgets_table.rb'
+    ]
+  end
+
+  let(:cutoff) { Date.parse('2022-10-01') - 21 }
+
+  subject(:database) { fake_danger.new }
+
+  describe '#find_migration_files_before' do
+    it 'returns migrations that are before the cutoff' do
+      expect(database.find_migration_files_before(migration_files, cutoff).length).to eq(8)
+    end
+  end
+end
diff --git a/tooling/danger/database.rb b/tooling/danger/database.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4cfac7c4af44a04a1475d97557881bc792934247
--- /dev/null
+++ b/tooling/danger/database.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Tooling
+  module Danger
+    module Database
+      TIMESTAMP_MATCHER = /(?<timestamp>\d{14})/
+      MIGRATION_MATCHER = %r{\A(ee/)?db/(geo/)?(post_)?migrate/}
+
+      def find_migration_files_before(file_names, cutoff)
+        migrations = file_names.select { |f| f.match?(MIGRATION_MATCHER) }
+        migrations.select do |migration|
+          next unless match = TIMESTAMP_MATCHER.match(migration)
+
+          timestamp = Date.parse(match[:timestamp])
+          timestamp < cutoff
+        end
+      end
+    end
+  end
+end