diff --git a/.woodpecker/docker.yaml b/.woodpecker/docker.yaml
index 16fbee026..0363b4693 100644
--- a/.woodpecker/docker.yaml
+++ b/.woodpecker/docker.yaml
@@ -197,8 +197,7 @@ steps:
       repo: *publish_repos_server
       dockerfile: docker/Dockerfile.server.multiarch
       platforms: *platforms_server
-      # remove 'latest' on older version branches to avoid accidental downgrade
-      tag: [latest, '${CI_COMMIT_TAG}']
+      tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}']
       logins: *publish_logins
     when: &when-release
       event: tag
@@ -211,8 +210,7 @@ steps:
       repo: *publish_repos_server
       dockerfile: docker/Dockerfile.server.alpine.multiarch
       platforms: *platforms_alpine
-      # remove 'latest-alpine' on older version branches to avoid accidental downgrade
-      tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
+      tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
       logins: *publish_logins
     when: *when-release
 
@@ -292,8 +290,7 @@ steps:
       repo: *publish_repos_agent
       dockerfile: docker/Dockerfile.agent.multiarch
       platforms: *platforms_release
-      # remove 'latest' on older version branches to avoid accidental downgrade
-      tag: [latest, '${CI_COMMIT_TAG}']
+      tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}', '${CI_COMMIT_TAG}']
       logins: *publish_logins
       build_args: *build_args
     when: *when-release
@@ -309,8 +306,7 @@ steps:
       repo: *publish_repos_agent
       dockerfile: docker/Dockerfile.agent.alpine.multiarch
       platforms: *platforms_alpine
-      # remove 'latest-alpine' on older version branches to avoid accidental downgrade
-      tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
+      tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
       logins: *publish_logins
       build_args: *build_args
     when: *when-release
@@ -388,8 +384,7 @@ steps:
       repo: *publish_repos_cli
       dockerfile: docker/Dockerfile.cli.multiarch
       platforms: *platforms_release
-      # remove 'latest' on older version branches to avoid accidental downgrade
-      tag: [latest, '${CI_COMMIT_TAG}']
+      tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}', '${CI_COMMIT_TAG}']
       logins: *publish_logins
       build_args: *build_args
     when: *when-release
@@ -405,8 +400,7 @@ steps:
       repo: *publish_repos_cli
       dockerfile: docker/Dockerfile.cli.alpine.multiarch
       platforms: *platforms_alpine
-      # remove 'latest-alpine' on older version branches to avoid accidental downgrade
-      tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
+      tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
       logins: *publish_logins
       build_args: *build_args
     when: *when-release
diff --git a/docker-compose.example.yaml b/docker-compose.example.yaml
index 6ce862d79..f54121f7f 100644
--- a/docker-compose.example.yaml
+++ b/docker-compose.example.yaml
@@ -2,7 +2,7 @@ version: '3'
 
 services:
   woodpecker-server:
-    image: woodpeckerci/woodpecker-server:latest
+    image: woodpeckerci/woodpecker-server:v3
     ports:
       - 8000:8000
     networks:
@@ -21,7 +21,7 @@ services:
     depends_on:
       woodpecker-server:
         condition: service_healthy
-    image: woodpeckerci/woodpecker-agent:latest
+    image: woodpeckerci/woodpecker-agent:v3
     networks:
       - woodpecker
     volumes:
diff --git a/docs/docs/30-administration/05-deployment-methods/10-docker-compose.md b/docs/docs/30-administration/05-deployment-methods/10-docker-compose.md
index a00353d3a..a9d59c9d7 100644
--- a/docs/docs/30-administration/05-deployment-methods/10-docker-compose.md
+++ b/docs/docs/30-administration/05-deployment-methods/10-docker-compose.md
@@ -115,21 +115,26 @@ The server and agents use a shared secret to authenticate communication. This sh
 
 Image variants:
 
-- The `latest` image is the latest stable release
 - The `vX.X.X` images are stable releases
-- The `vX.X` images are based on the current release branch (e.g. `release/v1.0`) and can be used to get bugfixes asap
+- The `vX.X` images are based on the current release branch (e.g. `release/v1.0`) and can be used to get bug fixes asap
+- The `vX` same as `vX.X` variant but also includes feature releases
 - The `next` images are based on the current `main` branch
 
+:::note
+The `latest` tag is not available on purpose (and has been dropped with the 3.x release) to prevent accidental major version upgrades.
+Hence, users are forced to specify a fixed or rolling tag, omitting the tag identifier (which equals to pulling `latest` implicitly) won't work.
+:::
+
 ```bash
 # server
-docker pull woodpeckerci/woodpecker-server:latest
-docker pull woodpeckerci/woodpecker-server:latest-alpine
+docker pull woodpeckerci/woodpecker-server:v3
+docker pull woodpeckerci/woodpecker-server:v3-alpine
 
 # agent
-docker pull woodpeckerci/woodpecker-agent:latest
-docker pull woodpeckerci/woodpecker-agent:latest-alpine
+docker pull woodpeckerci/woodpecker-agent:v3
+docker pull woodpeckerci/woodpecker-agent:v3-alpine
 
 # cli
-docker pull woodpeckerci/woodpecker-cli:latest
-docker pull woodpeckerci/woodpecker-cli:latest-alpine
+docker pull woodpeckerci/woodpecker-cli:v3
+docker pull woodpeckerci/woodpecker-cli:v3-alpine
 ```
diff --git a/docs/src/pages/migrations.md b/docs/src/pages/migrations.md
index 86588173c..cc210585f 100644
--- a/docs/src/pages/migrations.md
+++ b/docs/src/pages/migrations.md
@@ -135,6 +135,11 @@ The following restructuring was done to achieve a more consistent grouping:
 
 ### Admin-facing migrations
 
+#### Image tags
+
+- The `latest` tag has been dropped to avoid accidental major version upgrades.
+  A dedicated semver tag specification must be used, i.e., either a fixed version (like `v3.0.0`) or a rolling tag (e.g. `v3.0` or `v3`).
+
 - Previously, some (official) plugins were granted the `privileged` option by default to allow simplified usage.
   To streamline this process and enhance security transparency, no plugin is granted the `privileged` options by default anymore.
   To allow the use of these plugins in >= 3.0, they must be set explicitly through `WOODPECKER_PLUGINS_PRIVILEGED` on the admin side.