diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b7c00e180fd8558fb9ff38e4dea7f30f2a24a66a..50ee7102625dd7b49b0630aadffb93f96d6afae5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,6 +10,7 @@ stages:
   - qa
   - post-qa
   - pages
+  - notify
 
 # always use `gitlab-org` runners, however
 # in cases where jobs require Docker-in-Docker, the job
@@ -81,3 +82,4 @@ include:
   - local: .gitlab/ci/test-metadata.gitlab-ci.yml
   - local: .gitlab/ci/yaml.gitlab-ci.yml
   - local: .gitlab/ci/releases.gitlab-ci.yml
+  - local: .gitlab/ci/notify.gitlab-ci.yml
diff --git a/.gitlab/ci/notify.gitlab-ci.yml b/.gitlab/ci/notify.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fcdd5ee97d2067993e86d2fb99c611da923815b6
--- /dev/null
+++ b/.gitlab/ci/notify.gitlab-ci.yml
@@ -0,0 +1,23 @@
+.notify-slack:
+  image: alpine
+  stage: notify
+  dependencies: []
+  cache: {}
+  before_script:
+    - apk update && apk add git curl bash
+
+notify-update-gitaly:
+  extends:
+    - .notify-slack
+  rules:
+    - if: '$CI_MERGE_REQUEST_IID && $CI_COMMIT_BRANCH == $GITALY_UPDATE_BRANCH'
+      when: on_failure
+      allow_failure: true
+  variables:
+    NOTIFY_CHANNEL: g_create_gitaly
+    GITALY_UPDATE_BRANCH: release-tools/update-gitaly
+    MERGE_REQUEST_URL: ${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}
+  script:
+    - echo "NOTIFY_CHANNEL is ${NOTIFY_CHANNEL}"
+    - echo "CI_PIPELINE_URL is ${CI_PIPELINE_URL}"
+    - scripts/slack ${NOTIFY_CHANNEL} "☠️ \`${GITALY_UPDATE_BRANCH}\` failed! ☠️ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing
diff --git a/scripts/slack b/scripts/slack
new file mode 100755
index 0000000000000000000000000000000000000000..60bc70a8542d2d6e6916a91474f419c1c08bc84a
--- /dev/null
+++ b/scripts/slack
@@ -0,0 +1,17 @@
+#!/bin/bash
+# This is copied from:
+# https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/bin/slack
+#
+# Sends Slack notification MSG to CI_SLACK_WEBHOOK_URL (which needs to be set).
+# ICON_EMOJI needs to be set to an icon emoji name (without the `:` around it).
+
+CHANNEL=$1
+MSG=$2
+ICON_EMOJI=$3
+
+if [ -z "$CHANNEL" ] || [ -z "$CI_SLACK_WEBHOOK_URL" ] || [ -z "$MSG" ] || [ -z "$ICON_EMOJI" ]; then
+    echo "Missing argument(s) - Use: $0 channel message icon_emoji"
+    echo "and set CI_SLACK_WEBHOOK_URL environment variable."
+else
+    curl -X POST --data-urlencode 'payload={"channel": "#'"$CHANNEL"'", "username": "GitLab QA Bot", "text": "'"$MSG"'", "icon_emoji": "'":$ICON_EMOJI:"'"}' "$CI_SLACK_WEBHOOK_URL"
+fi