diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 2754a7da14e2dbe4ddc3ace1d9fde62c5fc3d71a..8ff39da581321f181ba06744d8adb27920460d11 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -1540,6 +1540,24 @@
                   }
                 }
               ]
+            },
+            "exit_codes": {
+              "markdownDescription": "Either a single or array of exit codes to trigger job retry on. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#retryexit_codes).",
+              "oneOf": [
+                {
+                  "description": "Retry when the job exit code is included in the array's values.",
+                  "type": "array",
+                  "minItems": 1,
+                  "uniqueItems": true,
+                  "items": {
+                    "type": "integer"
+                  }
+                },
+                {
+                  "description": "Retry when the job exit code is equal to.",
+                  "type": "integer"
+                }
+              ]
             }
           }
         }
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 83976bc0cfb7dd68bac0ed03cdb33657c0635d20..2535432cca647052228408077700d535a9d5834d 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -3793,7 +3793,7 @@ If not defined, defaults to `0` and jobs do not retry.
 When a job fails, the job is processed up to two more times, until it succeeds or
 reaches the maximum number of retries.
 
-By default, all failure types cause the job to be retried. Use [`retry:when`](#retrywhen)
+By default, all failure types cause the job to be retried. Use [`retry:when`](#retrywhen) or [`retry:exit_codes`](#retryexit_codes)
 to select which failures to retry on.
 
 **Keyword type**: Job keyword. You can use it only as part of a job or in the
@@ -3809,8 +3809,20 @@ to select which failures to retry on.
 test:
   script: rspec
   retry: 2
+
+test_advanced:
+  script:
+    - echo "Run a script that results in exit code 137."
+    - exit 137
+  retry:
+    max: 2
+    when: runner_system_failure
+    exit_codes: 137
 ```
 
+`test_advanced` will be retried up to 2 times if the exit code is `137` or if it had
+a runner system failure.
+
 #### `retry:when`
 
 Use `retry:when` with `retry:max` to retry jobs for only specific failure cases.
@@ -3872,6 +3884,48 @@ test:
       - stuck_or_timeout_failure
 ```
 
+#### `retry:exit_codes`
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/430037) in GitLab 16.10 [with a flag](../../administration/feature_flags.md) named `ci_retry_on_exit_codes`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flag](../../administration/feature_flags.md) named `ci_retry_on_exit_codes`.
+
+Use `retry:exit_codes` with `retry:max` to retry jobs for only specific failure cases.
+`retry:max` is the maximum number of retries, like [`retry`](#retry), and can be
+`0`, `1`, or `2`.
+
+**Keyword type**: Job keyword. You can use it only as part of a job or in the
+[`default` section](#default).
+
+**Possible inputs**:
+
+- A single exit code.
+- An array of exit codes.
+
+**Example of `retry:exit_codes`**:
+
+```yaml
+test_job_1:
+  script:
+    - echo "Run a script that results in exit code 1. This job isn't retried."
+    - exit 1
+  retry:
+    max: 2
+    exit_codes: 137
+
+test_job_2:
+  script:
+    - echo "Run a script that results in exit code 137. This job will be retried."
+    - exit 137
+  retry:
+    max: 1
+    exit_codes:
+      - 255
+      - 137
+```
+
 **Related topics**:
 
 You can specify the number of [retry attempts for certain stages of job execution](../runners/configure_runners.md#job-stages-attempts)
diff --git a/spec/frontend/editor/schema/ci/ci_schema_spec.js b/spec/frontend/editor/schema/ci/ci_schema_spec.js
index d6424336f43baafe35f24023c0d6d89c99253b15..0d74355d3053671c4a15191bb5f916a09f64bb04 100644
--- a/spec/frontend/editor/schema/ci/ci_schema_spec.js
+++ b/spec/frontend/editor/schema/ci/ci_schema_spec.js
@@ -43,6 +43,7 @@ import WorkflowAutoCancelOnNewCommitYaml from './yaml_tests/positive_tests/workf
 import WorkflowRulesAutoCancelOnJobFailureYaml from './yaml_tests/positive_tests/workflow/rules/auto_cancel/on_job_failure.yml';
 import WorkflowRulesAutoCancelOnNewCommitYaml from './yaml_tests/positive_tests/workflow/rules/auto_cancel/on_new_commit.yml';
 import StagesYaml from './yaml_tests/positive_tests/stages.yml';
+import RetryYaml from './yaml_tests/positive_tests/retry.yml';
 
 // YAML NEGATIVE TEST
 import ArtifactsNegativeYaml from './yaml_tests/negative_tests/artifacts.yml';
@@ -74,6 +75,7 @@ import WorkflowAutoCancelOnNewCommitNegativeYaml from './yaml_tests/negative_tes
 import WorkflowRulesAutoCancelOnJobFailureNegativeYaml from './yaml_tests/negative_tests/workflow/rules/auto_cancel/on_job_failure.yml';
 import WorkflowRulesAutoCancelOnNewCommitNegativeYaml from './yaml_tests/negative_tests/workflow/rules/auto_cancel/on_new_commit.yml';
 import StagesNegativeYaml from './yaml_tests/negative_tests/stages.yml';
+import RetryNegativeYaml from './yaml_tests/negative_tests/retry.yml';
 
 const ajv = new Ajv({
   strictTypes: false,
@@ -122,6 +124,7 @@ describe('positive tests', () => {
       WorkflowRulesAutoCancelOnJobFailureYaml,
       WorkflowRulesAutoCancelOnNewCommitYaml,
       StagesYaml,
+      RetryYaml,
     }),
   )('schema validates %s', (_, input) => {
     // We construct a new "JSON" from each main key that is inside a
@@ -172,6 +175,7 @@ describe('negative tests', () => {
       WorkflowRulesAutoCancelOnJobFailureNegativeYaml,
       WorkflowRulesAutoCancelOnNewCommitNegativeYaml,
       StagesNegativeYaml,
+      RetryNegativeYaml,
     }),
   )('schema validates %s', (_, input) => {
     // We construct a new "JSON" from each main key that is inside a
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/retry.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/retry.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7258521ec647dbaae288fa5ee3075607671fedc8
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/retry.yml
@@ -0,0 +1,60 @@
+# invalid retry
+invalid_job_with_retry_int:
+  stage: "test"
+  script: "rspec"
+  retry: -1
+
+invalid_job_with_retry_type:
+  stage: "test"
+  script: "rspec"
+  retry: "2"
+
+invalid_job_with_retry_object_type:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    unknown: 2
+
+# invalid retry:when
+invalid_job_with_retry_single_when_reason:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    when: "gitlab-ci-retry-object-unknown-when"
+
+invalid_job_with_retry_when_reason:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    when:
+      - "api_failure"
+      - "gitlab-ci-retry-object-unknown-when"
+
+# invalid retry:exit_codes
+invalid_job_with_retry_single_exit_codes_type:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    exit_codes: "137"
+
+invalid_job_with_retry_exit_codes_type:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    exit_codes:
+      - 137
+      - "1"
+
+invalid_job_with_retry_exit_codes_duplicate:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    exit_codes:
+      - 137
+      - 137
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/retry.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/retry.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c6c1f105531f2118ffcf568ad66ba95f0c65ff4a
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/retry.yml
@@ -0,0 +1,94 @@
+# valid retry
+valid_job_with_retry_int:
+  stage: "test"
+  script: "rspec"
+  retry: 2
+
+valid_job_with_retry_object_max:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+
+valid_job_with_retry_object_when:
+  stage: "test"
+  script: "rspec"
+  retry:
+    when: "runner_system_failure"
+
+valid_job_with_retry_object_exit_codes:
+  stage: "test"
+  script: "rspec"
+  retry:
+    exit_codes: 137
+
+valid_job_with_retry_object_all_properties:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 1
+    when: "runner_system_failure"
+    exit_codes: 137
+
+# valid retry:when
+valid_job_with_retry_single_when:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    when: "runner_system_failure"
+
+valid_job_with_retry_multiple_when:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    when:
+      - "runner_system_failure"
+      - "stuck_or_timeout_failure"
+
+valid_job_with_retry_all_when:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    when:
+      - "always"
+      - "unknown_failure"
+      - "script_failure"
+      - "api_failure"
+      - "stuck_or_timeout_failure"
+      - "runner_system_failure"
+      - "runner_unsupported"
+      - "stale_schedule"
+      - "job_execution_timeout"
+      - "archived_failure"
+      - "unmet_prerequisites"
+      - "scheduler_failure"
+      - "data_integrity_failure"
+
+valid_job_with_retry_duplicate_when:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    when:
+      - "runner_system_failure"
+      - "runner_system_failure"
+
+# valid retry:exit_codes
+valid_job_with_retry_single_exit_codes:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    exit_codes: 137
+
+valid_job_with_retry_multiple_exit_codes:
+  stage: "test"
+  script: "rspec"
+  retry:
+    max: 2
+    exit_codes:
+      - 137
+      - 255