diff --git a/.github/fixtures/test-bump-version-keep-zerover/cliff.toml b/.github/fixtures/test-bump-version-keep-zerover/cliff.toml
new file mode 100644
index 0000000000..15414304ae
--- /dev/null
+++ b/.github/fixtures/test-bump-version-keep-zerover/cliff.toml
@@ -0,0 +1,31 @@
+[changelog]
+# changelog header
+header = """
+# Changelog\n
+All notable changes to this project will be documented in this file.\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    ## [{{ version | trim_start_matches(pat="v") }}]
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | upper_first }}
+    {% for commit in commits %}
+        - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
+    {% endfor %}
+{% endfor %}\n
+"""
+# template for the changelog footer
+footer = """
+<!-- generated by git-cliff -->
+"""
+# remove the leading and trailing whitespace from the templates
+trim = true
+
+[bump]
+features_always_bump_minor = false
+breaking_always_bump_major = false
diff --git a/.github/fixtures/test-bump-version-keep-zerover/commit.sh b/.github/fixtures/test-bump-version-keep-zerover/commit.sh
new file mode 100755
index 0000000000..0fd84c20f6
--- /dev/null
+++ b/.github/fixtures/test-bump-version-keep-zerover/commit.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -e
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 1"
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 2"
+git tag v0.1.0
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "feat!: add breaking feature"
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "fix: fix feature 2"
diff --git a/.github/fixtures/test-bump-version-keep-zerover/expected.md b/.github/fixtures/test-bump-version-keep-zerover/expected.md
new file mode 100644
index 0000000000..b222642be6
--- /dev/null
+++ b/.github/fixtures/test-bump-version-keep-zerover/expected.md
@@ -0,0 +1,22 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [0.2.0]
+
+### Feat
+
+- [**breaking**] Add breaking feature
+
+### Fix
+
+- Fix feature 2
+
+## [0.1.0]
+
+### Feat
+
+- Add feature 1
+- Add feature 2
+
+<!-- generated by git-cliff -->
diff --git a/.github/fixtures/test-bump-version/commit.sh b/.github/fixtures/test-bump-version/commit.sh
index 3d7ef4718b..0fd84c20f6 100755
--- a/.github/fixtures/test-bump-version/commit.sh
+++ b/.github/fixtures/test-bump-version/commit.sh
@@ -5,5 +5,5 @@ GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add
 GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 2"
 git tag v0.1.0
 
-GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "fix: fix feature 1"
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "feat!: add breaking feature"
 GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "fix: fix feature 2"
diff --git a/.github/fixtures/test-bump-version/expected.md b/.github/fixtures/test-bump-version/expected.md
index a42c65aca8..5fbc9b8aeb 100644
--- a/.github/fixtures/test-bump-version/expected.md
+++ b/.github/fixtures/test-bump-version/expected.md
@@ -2,11 +2,14 @@
 
 All notable changes to this project will be documented in this file.
 
-## [0.1.1]
+## [1.0.0]
+
+### Feat
+
+- [**breaking**] Add breaking feature
 
 ### Fix
 
-- Fix feature 1
 - Fix feature 2
 
 ## [0.1.0]
diff --git a/git-cliff-core/src/changelog.rs b/git-cliff-core/src/changelog.rs
index 358d7d4d04..ac0998ea1f 100644
--- a/git-cliff-core/src/changelog.rs
+++ b/git-cliff-core/src/changelog.rs
@@ -200,7 +200,8 @@ impl<'a> Changelog<'a> {
 	pub fn bump_version(&mut self) -> Result<Option<String>> {
 		if let Some(ref mut last_release) = self.releases.iter_mut().next() {
 			if last_release.version.is_none() {
-				let next_version = last_release.calculate_next_version()?;
+				let next_version = last_release
+					.calculate_next_version_with_config(&self.config.bump)?;
 				debug!("Bumping the version to {next_version}");
 				last_release.version = Some(next_version.to_string());
 				last_release.timestamp = SystemTime::now()
@@ -307,6 +308,7 @@ impl<'a> Changelog<'a> {
 mod test {
 	use super::*;
 	use crate::config::{
+		Bump,
 		ChangelogConfig,
 		CommitParser,
 		GitConfig,
@@ -485,6 +487,7 @@ mod test {
 					token: None,
 				},
 			},
+			bump:      Bump::default(),
 		};
 		let test_release = Release {
 			version: Some(String::from("v1.0.0")),
diff --git a/git-cliff-core/src/config.rs b/git-cliff-core/src/config.rs
index f0f5be9805..90caea4ff0 100644
--- a/git-cliff-core/src/config.rs
+++ b/git-cliff-core/src/config.rs
@@ -33,6 +33,9 @@ pub struct Config {
 	/// Configuration values about remote.
 	#[serde(default)]
 	pub remote:    RemoteConfig,
+	/// Configuration values about bump version.
+	#[serde(default)]
+	pub bump:      Bump,
 }
 
 /// Changelog configuration.
@@ -136,6 +139,29 @@ impl Remote {
 	}
 }
 
+/// Bump version configuration.
+#[derive(Debug, Default, Clone, Serialize, Deserialize)]
+pub struct Bump {
+	/// Configures automatic minor version increments for feature changes.
+	///
+	/// When `true`, a feature will always trigger a minor version update.
+	/// When `false`, a feature will trigger:
+	///
+	/// - A patch version update if the major version is 0.
+	/// - A minor version update otherwise.
+	pub features_always_bump_minor: Option<bool>,
+
+	/// Configures 0 -> 1 major version increments for breaking changes.
+	///
+	/// When `true`, a breaking change commit will always trigger a major
+	/// version update (including the transition from version 0 to 1)
+	/// When `false`, a breaking change commit will trigger:
+	///
+	/// - A minor version update if the major version is 0.
+	/// - A major version update otherwise.
+	pub breaking_always_bump_major: Option<bool>,
+}
+
 /// Parser for grouping commits.
 #[derive(Debug, Default, Clone, Serialize, Deserialize)]
 pub struct CommitParser {
diff --git a/git-cliff-core/src/release.rs b/git-cliff-core/src/release.rs
index b1930daf3b..34a5c40557 100644
--- a/git-cliff-core/src/release.rs
+++ b/git-cliff-core/src/release.rs
@@ -1,4 +1,5 @@
 use crate::commit::Commit;
+use crate::config::Bump;
 use crate::error::Result;
 #[cfg(feature = "github")]
 use crate::github::{
@@ -98,7 +99,21 @@ impl<'a> Release<'a> {
 	}
 
 	/// Calculates the next version based on the commits.
+	///
+	/// It uses the default bump version configuration to calculate the next
+	/// version.
 	pub fn calculate_next_version(&self) -> Result<String> {
+		self.calculate_next_version_with_config(&Bump::default())
+	}
+
+	/// Calculates the next version based on the commits.
+	///
+	/// It uses the given bump version configuration to calculate the next
+	/// version.
+	pub(super) fn calculate_next_version_with_config(
+		&self,
+		config: &Bump,
+	) -> Result<String> {
 		match self
 			.previous
 			.as_ref()
@@ -126,8 +141,12 @@ impl<'a> Release<'a> {
 					}
 				}
 				let next_version = VersionUpdater::new()
-					.with_features_always_increment_minor(true)
-					.with_breaking_always_increment_major(true)
+					.with_features_always_increment_minor(
+						config.features_always_bump_minor.unwrap_or(true),
+					)
+					.with_breaking_always_increment_major(
+						config.breaking_always_bump_major.unwrap_or(true),
+					)
 					.increment(
 						&semver?,
 						self.commits
@@ -169,7 +188,27 @@ mod test {
 	use super::*;
 	#[test]
 	fn bump_version() -> Result<()> {
-		for (version, expected_version, commits) in [
+		fn build_release<'a>(version: &str, commits: &'a [&str]) -> Release<'a> {
+			Release {
+				version: None,
+				commits: commits
+					.iter()
+					.map(|v| Commit::from(v.to_string()))
+					.collect(),
+				commit_id: None,
+				timestamp: 0,
+				previous: Some(Box::new(Release {
+					version: Some(String::from(version)),
+					..Default::default()
+				})),
+				#[cfg(feature = "github")]
+				github: crate::github::GitHubReleaseMetadata {
+					contributors: vec![],
+				},
+			}
+		}
+
+		let test_shared = [
 			("1.0.0", "1.1.0", vec!["feat: add xyz", "fix: fix xyz"]),
 			("1.0.0", "1.0.1", vec!["fix: add xyz", "fix: aaaaaa"]),
 			("1.0.0", "2.0.0", vec!["feat!: add xyz", "feat: zzz"]),
@@ -202,27 +241,87 @@ mod test {
 				"aaa#/@#$@9384!#%^#@#@!#!239432413-idk-9999.2200.5932-alpha.420",
 				vec!["feat: damn this is working"],
 			),
-		] {
-			let release = Release {
-				version: None,
-				commits: commits
-					.into_iter()
-					.map(|v| Commit::from(v.to_string()))
-					.collect(),
-				commit_id: None,
-				timestamp: 0,
-				previous: Some(Box::new(Release {
-					version: Some(String::from(version)),
-					..Default::default()
-				})),
-				#[cfg(feature = "github")]
-				github: crate::github::GitHubReleaseMetadata {
-					contributors: vec![],
-				},
-			};
+		];
+
+		for (version, expected_version, commits) in test_shared.iter().chain(
+			[
+				("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
+				("0.0.1", "0.1.0", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.0.1", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
+				("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
+				("0.1.0", "0.2.0", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.1.0", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
+			]
+			.iter(),
+		) {
+			let release = build_release(version, commits);
 			let next_version = release.calculate_next_version()?;
-			assert_eq!(expected_version, next_version);
+			assert_eq!(expected_version, &next_version);
+			let next_version =
+				release.calculate_next_version_with_config(&Bump::default())?;
+			assert_eq!(expected_version, &next_version);
+		}
+
+		for (version, expected_version, commits) in test_shared.iter().chain(
+			[
+				("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
+				("0.0.1", "0.0.2", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.0.1", "0.0.2", vec!["feat!: add xyz", "feat: zzz"]),
+				("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
+				("0.1.0", "0.1.1", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.1.0", "0.2.0", vec!["feat!: add xyz", "feat: zzz"]),
+			]
+			.iter(),
+		) {
+			let release = build_release(version, commits);
+			let next_version =
+				release.calculate_next_version_with_config(&Bump {
+					features_always_bump_minor: Some(false),
+					breaking_always_bump_major: Some(false),
+				})?;
+			assert_eq!(expected_version, &next_version);
+		}
+
+		for (version, expected_version, commits) in test_shared.iter().chain(
+			[
+				("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
+				("0.0.1", "0.1.0", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.0.1", "0.1.0", vec!["feat!: add xyz", "feat: zzz"]),
+				("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
+				("0.1.0", "0.2.0", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.1.0", "0.2.0", vec!["feat!: add xyz", "feat: zzz"]),
+			]
+			.iter(),
+		) {
+			let release = build_release(version, commits);
+			let next_version =
+				release.calculate_next_version_with_config(&Bump {
+					features_always_bump_minor: Some(true),
+					breaking_always_bump_major: Some(false),
+				})?;
+			assert_eq!(expected_version, &next_version);
+		}
+
+		for (version, expected_version, commits) in test_shared.iter().chain(
+			[
+				("0.0.1", "0.0.2", vec!["fix: fix xyz"]),
+				("0.0.1", "0.0.2", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.0.1", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
+				("0.1.0", "0.1.1", vec!["fix: fix xyz"]),
+				("0.1.0", "0.1.1", vec!["feat: add xyz", "fix: fix xyz"]),
+				("0.1.0", "1.0.0", vec!["feat!: add xyz", "feat: zzz"]),
+			]
+			.iter(),
+		) {
+			let release = build_release(version, commits);
+			let next_version =
+				release.calculate_next_version_with_config(&Bump {
+					features_always_bump_minor: Some(false),
+					breaking_always_bump_major: Some(true),
+				})?;
+			assert_eq!(expected_version, &next_version);
 		}
+
 		let empty_release = Release {
 			previous: Some(Box::new(Release {
 				version: None,
@@ -230,8 +329,18 @@ mod test {
 			})),
 			..Default::default()
 		};
-		let next_version = empty_release.calculate_next_version()?;
-		assert_eq!("0.1.0", next_version);
+		assert_eq!("0.1.0", empty_release.calculate_next_version()?);
+		for (features_always_bump_minor, breaking_always_bump_major) in
+			[(true, true), (true, false), (false, true), (false, false)]
+		{
+			assert_eq!(
+				"0.1.0",
+				empty_release.calculate_next_version_with_config(&Bump {
+					features_always_bump_minor: Some(features_always_bump_minor),
+					breaking_always_bump_major: Some(breaking_always_bump_major),
+				})?
+			);
+		}
 		Ok(())
 	}
 
diff --git a/website/docs/configuration/bump.md b/website/docs/configuration/bump.md
new file mode 100644
index 0000000000..7bda75e63a
--- /dev/null
+++ b/website/docs/configuration/bump.md
@@ -0,0 +1,28 @@
+# `bump`
+
+This section contains the bump version related configuration options.
+
+```toml
+[bump]
+features_always_bump_minor = true
+breaking_always_bump_major = true
+```
+
+### features_always_bump_minor
+
+Configures automatic minor version increments for feature changes.
+When `true`, a feature will always trigger a minor version update.
+When `false`, a feature will trigger:
+
+- A patch version update if the major version is 0.
+- A minor version update otherwise.
+
+### breaking_always_bump_major
+
+Configures 0 -> 1 major version increments for breaking changes.
+When `true`, a breaking change commit will always trigger a major version update
+(including the transition from version 0 to 1)
+When `false`, a breaking change commit will trigger:
+
+- A minor version update if the major version is 0.
+- A major version update otherwise.
diff --git a/website/docs/usage/bump-version.md b/website/docs/usage/bump-version.md
index c7f1389c8d..902d92bc87 100644
--- a/website/docs/usage/bump-version.md
+++ b/website/docs/usage/bump-version.md
@@ -29,3 +29,12 @@ Tip: you can also get the bumped version [from the context](/docs/usage/print-co
 ```bash
 git cliff --unreleased --bump --context | jq -r .[0].version
 ```
+
+## Zero-based versioning scheme
+
+When working with a zero-based versioning scheme (i.e., `0.x.y` or `0.0.x`),
+it is often desirable to preserve the leading zero even when introducing a breaking change.
+A switch from `0` to `1` should indicate a higher API stability level.
+
+You can modify the bumping rules to preserve the zero-based versioning scheme in the
+[configuration file](/docs/configuration/bump).