diff --git a/db/post_migrate/20231129132636_prepare_indexes_for_partitioning_ci_pipeline_variables.rb b/db/post_migrate/20231129132636_prepare_indexes_for_partitioning_ci_pipeline_variables.rb
new file mode 100644
index 0000000000000000000000000000000000000000..efa0f6597e338b8968ade5a496021397459cbbac
--- /dev/null
+++ b/db/post_migrate/20231129132636_prepare_indexes_for_partitioning_ci_pipeline_variables.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class PrepareIndexesForPartitioningCiPipelineVariables < Gitlab::Database::Migration[2.2]
+  milestone '16.7'
+  disable_ddl_transaction!
+
+  TABLE_NAME = :ci_pipeline_variables
+  PK_INDEX_NAME = :index_ci_pipeline_variables_on_id_partition_id_unique
+  UNIQUE_INDEX_NAME = :index_pipeline_variables_on_pipeline_id_key_partition_id_unique
+
+  def up
+    add_concurrent_index(TABLE_NAME, %i[id partition_id], unique: true, name: PK_INDEX_NAME)
+    add_concurrent_index(TABLE_NAME, %i[pipeline_id key partition_id], unique: true, name: UNIQUE_INDEX_NAME)
+  end
+
+  def down
+    remove_concurrent_index_by_name(TABLE_NAME, PK_INDEX_NAME)
+    remove_concurrent_index_by_name(TABLE_NAME, UNIQUE_INDEX_NAME)
+  end
+end
diff --git a/db/post_migrate/20231130131808_remove_indexes_without_partition_id_from_ci_pipeline_variables.rb b/db/post_migrate/20231130131808_remove_indexes_without_partition_id_from_ci_pipeline_variables.rb
new file mode 100644
index 0000000000000000000000000000000000000000..39ba44dc0fd7c24f803d05a41d98c0760a60d46c
--- /dev/null
+++ b/db/post_migrate/20231130131808_remove_indexes_without_partition_id_from_ci_pipeline_variables.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class RemoveIndexesWithoutPartitionIdFromCiPipelineVariables < Gitlab::Database::Migration[2.2]
+  milestone '16.7'
+  disable_ddl_transaction!
+
+  TABLE_NAME = :ci_pipeline_variables
+  OLD_UNIQUE_INDEX_NAME = :index_ci_pipeline_variables_on_pipeline_id_and_key
+
+  def up
+    remove_concurrent_index_by_name(TABLE_NAME, OLD_UNIQUE_INDEX_NAME)
+  end
+
+  def down
+    add_concurrent_index(TABLE_NAME, %i[pipeline_id key], unique: true, name: OLD_UNIQUE_INDEX_NAME)
+  end
+end
diff --git a/db/schema_migrations/20231129132636 b/db/schema_migrations/20231129132636
new file mode 100644
index 0000000000000000000000000000000000000000..91703ace16bf39a52c25e5aa21c40e721c9f7d81
--- /dev/null
+++ b/db/schema_migrations/20231129132636
@@ -0,0 +1 @@
+1bdc6128604324a7bebec587ed935dfd2e91838f36e3ca68fadf695a48b32d24
\ No newline at end of file
diff --git a/db/schema_migrations/20231130131808 b/db/schema_migrations/20231130131808
new file mode 100644
index 0000000000000000000000000000000000000000..630f450ce7152e1fc87784c6fef5bcc24e01a8b8
--- /dev/null
+++ b/db/schema_migrations/20231130131808
@@ -0,0 +1 @@
+20c7fd677cfa00821b67761f9d406d1bf4cfdf65831c3c96910ccb43986b9926
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index b5de92bf170129247a6bc20392cc6c442a2e37d3..4084e589f0c864bc0946223288bed6567fca6b1a 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -32174,7 +32174,7 @@ CREATE INDEX index_ci_pipeline_schedules_on_owner_id_and_id_and_active ON ci_pip
 
 CREATE INDEX index_ci_pipeline_schedules_on_project_id ON ci_pipeline_schedules USING btree (project_id);
 
-CREATE UNIQUE INDEX index_ci_pipeline_variables_on_pipeline_id_and_key ON ci_pipeline_variables USING btree (pipeline_id, key);
+CREATE UNIQUE INDEX index_ci_pipeline_variables_on_id_partition_id_unique ON ci_pipeline_variables USING btree (id, partition_id);
 
 CREATE INDEX index_ci_pipelines_config_on_pipeline_id ON ci_pipelines_config USING btree (pipeline_id);
 
@@ -33940,6 +33940,8 @@ CREATE INDEX index_personal_access_tokens_on_user_id ON personal_access_tokens U
 
 CREATE INDEX index_pipeline_metadata_on_pipeline_id_name_text_pattern ON ci_pipeline_metadata USING btree (pipeline_id, name text_pattern_ops);
 
+CREATE UNIQUE INDEX index_pipeline_variables_on_pipeline_id_key_partition_id_unique ON ci_pipeline_variables USING btree (pipeline_id, key, partition_id);
+
 CREATE UNIQUE INDEX index_plan_limits_on_plan_id ON plan_limits USING btree (plan_id);
 
 CREATE UNIQUE INDEX index_plans_on_name ON plans USING btree (name);