diff --git a/db/docs/views/postgres_sequences.yml b/db/docs/views/postgres_sequences.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7937a5511bf3a361e7db1c05b547e9269e63d5e8
--- /dev/null
+++ b/db/docs/views/postgres_sequences.yml
@@ -0,0 +1,10 @@
+---
+view_name: postgres_sequences
+classes:
+  - Gitlab::Database::PostgresSequence
+feature_categories:
+  - database
+description: SQL view to get information about postgres sequences
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139117
+milestone: '16.7'
+gitlab_schema: gitlab_shared
diff --git a/db/migrate/20231207144215_add_postgres_sequences_view.rb b/db/migrate/20231207144215_add_postgres_sequences_view.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6187bb5f15ee86f946de415909f7e17c943e904a
--- /dev/null
+++ b/db/migrate/20231207144215_add_postgres_sequences_view.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class AddPostgresSequencesView < Gitlab::Database::Migration[2.2]
+  milestone '16.7'
+  enable_lock_retries!
+
+  def up
+    execute(<<~SQL)
+    CREATE OR REPLACE VIEW postgres_sequences
+    AS
+    SELECT seq_pg_class.relname AS seq_name,
+        dep_pg_class.relname AS table_name,
+        pg_attribute.attname AS col_name
+      FROM pg_class seq_pg_class
+      INNER JOIN pg_depend ON seq_pg_class.oid = pg_depend.objid
+      INNER JOIN pg_class dep_pg_class ON pg_depend.refobjid = dep_pg_class.oid
+      INNER JOIN pg_attribute ON dep_pg_class.oid = pg_attribute.attrelid
+      AND pg_depend.refobjsubid = pg_attribute.attnum
+      WHERE seq_pg_class.relkind = 'S'
+    SQL
+  end
+
+  def down
+    execute(<<~SQL)
+      DROP VIEW postgres_sequences;
+    SQL
+  end
+end
diff --git a/db/schema_migrations/20231207144215 b/db/schema_migrations/20231207144215
new file mode 100644
index 0000000000000000000000000000000000000000..971d491857792817b9a101221d1c2c812be38fd6
--- /dev/null
+++ b/db/schema_migrations/20231207144215
@@ -0,0 +1 @@
+871cc15f04f235ff2719eb334c28041a0f1093653e5ca2fad5e92b911622d221
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 3e55c8ff61552bbf7513ad0ead4c8cd4b9f9744b..3256c4b0e079ee08d1f03a8c3e5207e7e0130ce3 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -21617,6 +21617,16 @@ CREATE SEQUENCE postgres_reindex_queued_actions_id_seq
 
 ALTER SEQUENCE postgres_reindex_queued_actions_id_seq OWNED BY postgres_reindex_queued_actions.id;
 
+CREATE VIEW postgres_sequences AS
+ SELECT seq_pg_class.relname AS seq_name,
+    dep_pg_class.relname AS table_name,
+    pg_attribute.attname AS col_name
+   FROM (((pg_class seq_pg_class
+     JOIN pg_depend ON ((seq_pg_class.oid = pg_depend.objid)))
+     JOIN pg_class dep_pg_class ON ((pg_depend.refobjid = dep_pg_class.oid)))
+     JOIN pg_attribute ON (((dep_pg_class.oid = pg_attribute.attrelid) AND (pg_depend.refobjsubid = pg_attribute.attnum))))
+  WHERE (seq_pg_class.relkind = 'S'::"char");
+
 CREATE TABLE programming_languages (
     id integer NOT NULL,
     name character varying NOT NULL,
diff --git a/lib/gitlab/database/postgres_sequence.rb b/lib/gitlab/database/postgres_sequence.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bf394d80e12ddd9851d45f6009d1e63f951a84dd
--- /dev/null
+++ b/lib/gitlab/database/postgres_sequence.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Gitlab
+  module Database
+    # Backed by the postgres_sequences view
+    class PostgresSequence < SharedModel
+      self.primary_key = :seq_name
+
+      scope :by_table_name, ->(table_name) { where(table_name: table_name) }
+    end
+  end
+end
diff --git a/spec/lib/gitlab/database/postgres_sequences_spec.rb b/spec/lib/gitlab/database/postgres_sequences_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2373edaea18e36d9afb35358b5b6e7af58d41183
--- /dev/null
+++ b/spec/lib/gitlab/database/postgres_sequences_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::PostgresSequence, type: :model, feature_category: :database do
+  # PostgresSequence does not `behaves_like 'a postgres model'` because it does not correspond 1-1 with a single entry
+  # in pg_class
+  let(:schema) { ActiveRecord::Base.connection.current_schema }
+  let(:table_name) { '_test_table' }
+  let(:table_name_without_sequence) { '_test_table_without_sequence' }
+
+  before do
+    ActiveRecord::Base.connection.execute(<<~SQL)
+      CREATE TABLE #{table_name} (
+        id bigserial PRIMARY KEY NOT NULL
+      );
+
+      CREATE TABLE #{table_name_without_sequence} (
+        id bigint PRIMARY KEY NOT NULL
+      );
+    SQL
+  end
+
+  describe '#by_table_name' do
+    context 'when table does not have a sequence' do
+      it 'returns an empty collection' do
+        expect(described_class.by_table_name(table_name_without_sequence)).to be_empty
+      end
+    end
+
+    it 'returns the sequence for a given table' do
+      expect(described_class.by_table_name(table_name).first[:table_name]).to eq(table_name)
+    end
+  end
+end