diff --git a/README.md b/README.md
index 70a0e815135a55662cfc28afee406a9db4de2a9f..6855cf2e2e05ccf1d1d55f7795a127e0691d863c 100644
--- a/README.md
+++ b/README.md
@@ -159,23 +159,31 @@ It is bound to the `test` stage, and uses the following variables:
 | `MAVEN_SBOM_DISABLED` | Set to `true` to disable this job | _none_ |
 | `MAVEN_SBOM_GEN_ARGS` | Maven command used for SBOM analysis | `org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom` |
 
-### `mvn-snapshot` & `mvn-release` jobs
+### `mvn-release` & `mvn-deploy-*` jobs
 
-These jobs are **disabled by default** and perform, respectively, the following:
+These jobs are **disabled by default** and - when enabled - respectively perform the following:
 
-* a [Maven deploy](https://maven.apache.org/plugins/maven-deploy-plugin/) of your Java packages (jar, war, etc.),
-* a [Maven release](http://maven.apache.org/maven-release/maven-release-plugin/index.html) of your current branch.
+1. a [Maven release:prepare](https://maven.apache.org/maven-release/maven-release-plugin/usage/prepare-release.html) of your current branch
+    * only triggers the first part of the release (version changes in `pom.xml`, Git commits and version tag)
+    * provides a default integration with `semantic-release` ([see below](#semantic-release-integration))
+    * the second part of the release (package and publish to a Maven registry) is performed by the `mvn-deploy` job below
+2. a [Maven deploy](https://maven.apache.org/plugins/maven-deploy-plugin/) of your Java packages (jar, war, etc.) to any Maven-compliant registry
+    * `mvn-deploy-release` publishes the **stable** version on the tag pipeline triggered by a `mvn-release`,
+    * `mvn-deploy-snapshot` publishes the **snapshot** version on other branches.
 
 They are bound to the `publish` stage, and use the following variables:
 
 | Name                                | description                                                  | default value     |
 | ----------------------------------- | ------------------------------------------------------------ | ----------------- |
-| `MAVEN_DEPLOY_ENABLED`              | Set to `true` to enable a publish jobs                            | _none_ (disabled) |
-| `MAVEN_DEPLOY_FROM_UNPROTECTED_DISABLED`       | Set to `true` to limit snapshot publication to protected branches | _none_ (disabled) |
-| `MAVEN_DEPLOY_ARGS`                 | Maven arguments for the Snapshot job                         | `deploy -Dmaven.test.skip=true` |
-| `MAVEN_RELEASE_ARGS`                | Maven arguments for the Release job                          | `release:prepare release:perform -Darguments=-Dmaven.test.skip=true` |
-| `MAVEN_RELEASE_SCM_COMMENT_PREFIX`  | Maven release plugin [scmCommentPrefix](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmCommentPrefix) parameter  | `[ci skip][maven-release-plugin]` |
-| `MVN_SEMREL_RELEASE_DISABLED`  | Set to `true` to disable [semantic-release integration](#semantic-release-integration)   | _none_ (disabled) |
+| `MAVEN_DEPLOY_ENABLED`              | Set to `true` to enable release and publish jobs             | _none_ (disabled) |
+| `MAVEN_DEPLOY_FROM_UNPROTECTED_DISABLED`| Set to `true` to limit snapshot publication to protected branches | _none_ (disabled) |
+| `MAVEN_DEPLOY_ARGS`                 | Maven arguments for the `mvn-deploy` job                     | `deploy -Dmaven.test.skip=true` |
+| `MAVEN_RELEASE_ARGS`                | Maven arguments for the `mvn-release` job                    | `release:prepare -DtagNameFormat=@{project.version} -Darguments=-Dmaven.test.skip=true` |
+| `MAVEN_RELEASE_VERSION`             | Explicit version to use when triggering a release | _none_ (uses the current snapshot version from `pom.xml`) |
+| `MAVEN_RELEASE_SCM_COMMENT_PREFIX`  | Maven release plugin [scmCommentPrefix](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmCommentPrefix) parameter | `chore(maven-release): ` |
+| `MAVEN_RELEASE_SCM_RELEASE_COMMENT` | Maven release plugin [scmReleaseCommitComment](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmReleaseCommitComment) parameter (since Maven `3.0.0-M1`) | _none_ (Maven default) |
+| `MAVEN_RELEASE_SCM_DEV_COMMENT`     | Maven release plugin [scmDevelopmentCommitComment](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmDevelopmentCommitComment) parameter (since Maven `3.0.0-M1`) | _none_ (Maven default) |
+| `MVN_SEMREL_RELEASE_DISABLED`       | Set to `true` to disable [semantic-release integration](#semantic-release-integration)   | _none_ (disabled) |
 
 More info:
 
diff --git a/kicker.json b/kicker.json
index 5f14b7fe95bdb7e29bac6c6cf8f68fd020fcace2..b968e39aa9a5a87b8cbb4ec2f4eef5613da1167d 100644
--- a/kicker.json
+++ b/kicker.json
@@ -123,13 +123,13 @@
     {
       "id": "publish",
       "name": "Publish",
-      "description": "Publish [Snapshot](https://maven.apache.org/plugins/maven-deploy-plugin/) & [Releases](http://maven.apache.org/maven-release/maven-release-plugin) to a Nexus repository",
+      "description": "Publish [Snapshot](https://maven.apache.org/plugins/maven-deploy-plugin/) & [Releases](http://maven.apache.org/maven-release/maven-release-plugin) to a Maven-compliant repository",
       "enable_with": "MAVEN_DEPLOY_ENABLED",
       "variables": [
         {
           "name": "MAVEN_DEPLOY_ARGS",
-          "description": "Maven arguments for the Snapshot job",
-          "default": "deploy -DskipTests",
+          "description": "Maven arguments for the deploy job",
+          "default": "deploy -Dmaven.test.skip=true",
           "advanced": true
         },
         {
@@ -140,14 +140,29 @@
         },
         {
           "name": "MAVEN_RELEASE_ARGS",
-          "description": "Maven arguments for the Release job",
-          "default": "release:prepare release:perform -DskipTests",
+          "description": "Maven arguments for the release job",
+          "default": "release:prepare -DtagNameFormat=@{project.version} -Darguments=-Dmaven.test.skip=true",
+          "advanced": true
+        },
+        {
+          "name": "MAVEN_RELEASE_VERSION",
+          "description": "Explicit version to use when triggering a release\n\n_Otherwise uses the current snapshot version from `pom.xml`)_",
           "advanced": true
         },
         {
           "name": "MAVEN_RELEASE_SCM_COMMENT_PREFIX",
           "description": "Maven release plugin [scmCommentPrefix](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmCommentPrefix) parameter",
-          "default": "[ci skip][maven-release-plugin]",
+          "default": "chore(maven-release): ",
+          "advanced": true
+        },
+        {
+          "name": "MAVEN_RELEASE_SCM_RELEASE_COMMENT",
+          "description": "Maven release plugin [scmReleaseCommitComment](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmReleaseCommitComment) parameter\n\n(since Maven `3.0.0-M1`)",
+          "advanced": true
+        },
+        {
+          "name": "MAVEN_RELEASE_SCM_DEV_COMMENT",
+          "description": "Maven release plugin [scmDevelopmentCommitComment](https://maven.apache.org/maven-release/maven-release-plugin/prepare-mojo.html#scmDevelopmentCommitComment) parameter\n\n(since Maven `3.0.0-M1`)",
           "advanced": true
         },
         {
diff --git a/templates/gitlab-ci-maven.yml b/templates/gitlab-ci-maven.yml
index a484574493d4499800d1d016883468952e131710..5484b9be6518eed013d053be9d91d34e97f6139f 100644
--- a/templates/gitlab-ci-maven.yml
+++ b/templates/gitlab-ci-maven.yml
@@ -68,6 +68,8 @@ variables:
   PROD_REF: '/^(master|main)$/'
   # default integration ref name (pattern)
   INTEG_REF: '/^develop$/'
+  # default release tag name (pattern)
+  RELEASE_REF: '/^v?[0-9]+\.[0-9]+\.[0-9]+$/'
 
   # default configuration directory
   MAVEN_CFG_DIR: ".m2"
@@ -119,8 +121,8 @@ variables:
   MAVEN_DEPLOY_ARGS: "deploy -Dmaven.test.skip=true"
 
   # Maven release arguments
-  MAVEN_RELEASE_ARGS: "release:prepare release:perform -Darguments=-Dmaven.test.skip=true"
-  MAVEN_RELEASE_SCM_COMMENT_PREFIX: "[ci skip][maven-release-plugin]"
+  MAVEN_RELEASE_ARGS: "release:prepare -DtagNameFormat=@{project.version} -Darguments=-Dmaven.test.skip=true"
+  MAVEN_RELEASE_SCM_COMMENT_PREFIX: "chore(maven-release): "
 
 stages:
   - build
@@ -369,19 +371,20 @@ stages:
     fi
   }
 
-  function perform_snapshot() {
+  function mvn_deploy() {
     # shellcheck disable=SC2086
     pom_version=$(mvn $MAVEN_CLI_OPTS $mvn_settings_opt $java_proxy_args org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout | tail -n 1)
-    case $pom_version in
-        *-SNAPSHOT)
-            log_info "Snapshot version for pom (\\e[33;1m${pom_version}\\e[0m): deploy"
-            # shellcheck disable=SC2086
-            mvn ${TRACE+-X} $MAVEN_CLI_OPTS $mvn_settings_opt $java_proxy_args $MAVEN_DEPLOY_ARGS
-            ;;
-        *)
-            log_info "Not snapshot version for pom (\\e[33;1m${pom_version}\\e[0m): skip"
-            ;;
-    esac
+    if [[ "$CI_COMMIT_TAG" ]] && [[ "$pom_version" =~ -SNAPSHOT$ ]]
+    then
+      log_warn "Can't publish SNAPSHOT version \\e[33;1m${pom_version}\\e[0m from tag: skip"
+    elif [[ -z "$CI_COMMIT_TAG" ]] && [[ ! "$pom_version" =~ -SNAPSHOT$ ]]
+    then
+      log_warn "Can't publish non-SNAPSHOT version \\e[33;1m${pom_version}\\e[0m from branch: skip"
+    else
+      log_info "Publish version \\e[33;1m${pom_version}\\e[0m..."
+      # shellcheck disable=SC2086
+      mvn ${TRACE+-X} $MAVEN_CLI_OPTS $mvn_settings_opt $java_proxy_args $MAVEN_DEPLOY_ARGS
+    fi
   }
 
   unscope_variables
@@ -524,20 +527,32 @@ mvn-sbom:
       when: never
     - !reference [.test-policy, rules]
 
-mvn-snapshot:
+mvn-deploy-snapshot:
   extends: .mvn-base
   stage: publish
   script:
-    - perform_snapshot
+    - mvn_deploy
   rules:
+    # exclude if $MAVEN_DEPLOY_ENABLED not set
+    - if: '$MAVEN_DEPLOY_ENABLED != "true"'
+      when: never
     # on tags: never
     - if: $CI_COMMIT_TAG
       when: never
-    # exclude unprotected ref if specified
-    - if: '$MAVEN_DEPLOY_FROM_UNPROTECTED_DISABLED == "true" && $CI_COMMIT_REF_PROTECTED != "true"'
+    # exclude unprotected ref if disabled
+    - if: '$MAVEN_DEPLOY_FROM_UNPROTECTED_DISABLED != "true" || $CI_COMMIT_REF_PROTECTED == "true"'
+
+mvn-deploy-release:
+  extends: .mvn-base
+  stage: publish
+  script:
+    - mvn_deploy
+  rules:
+    # exclude if $MAVEN_DEPLOY_ENABLED not set
+    - if: '$MAVEN_DEPLOY_ENABLED != "true"'
       when: never
-    # else: if $MAVEN_DEPLOY_ENABLED is set
-    - if: '$MAVEN_DEPLOY_ENABLED == "true"'
+    # on tag with release pattern: auto
+    - if: '$CI_COMMIT_TAG =~ $RELEASE_REF'
 
 mvn-release:
   extends: .mvn-base
@@ -563,13 +578,19 @@ mvn-release:
           semrel_args="-DreleaseVersion=${SEMREL_INFO_NEXT_VERSION}"
         fi
       fi
-    - mvn ${TRACE+-X} $MAVEN_CLI_OPTS $mvn_settings_opt $java_proxy_args $scm_auth_args ${MAVEN_RELEASE_ARGS} ${semrel_args} -DscmCommentPrefix="$MAVEN_RELEASE_SCM_COMMENT_PREFIX"
+    - >-
+      mvn ${TRACE+-X} $MAVEN_CLI_OPTS $mvn_settings_opt $java_proxy_args
+      ${scm_auth_args} ${semrel_args}
+      ${MAVEN_RELEASE_VERSION+-DreleaseVersion="$MAVEN_RELEASE_VERSION"}
+      ${MAVEN_RELEASE_SCM_COMMENT_PREFIX+-DscmCommentPrefix="$MAVEN_RELEASE_SCM_COMMENT_PREFIX"}
+      ${MAVEN_RELEASE_SCM_RELEASE_COMMENT+-DscmReleaseCommitComment="$MAVEN_RELEASE_SCM_RELEASE_COMMENT"}
+      ${MAVEN_RELEASE_SCM_DEV_COMMENT+-DscmDevelopmentCommitComment="$MAVEN_RELEASE_SCM_DEV_COMMENT"}
+      ${MAVEN_RELEASE_ARGS}
   rules:
-    # on production branch(es): manual & non-blocking if $MAVEN_DEPLOY_ENABLED is set
-    - if: '$MAVEN_DEPLOY_ENABLED == "true" && $CI_COMMIT_REF_NAME =~ $PROD_REF'
-      when: manual
-      allow_failure: true
-    # on integration branch(es): manual & non-blocking if $MAVEN_DEPLOY_ENABLED is set
-    - if: '$MAVEN_DEPLOY_ENABLED == "true" && $CI_COMMIT_REF_NAME =~ $INTEG_REF'
+    # exclude if $MAVEN_DEPLOY_ENABLED not set
+    - if: '$MAVEN_DEPLOY_ENABLED != "true"'
+      when: never
+    # on production or integration branch: manual, non blocking
+    - if: '$CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF'
       when: manual
       allow_failure: true