diff --git a/lib/versioning/npm/index.spec.ts b/lib/versioning/npm/index.spec.ts
index 510f0652a8767ec4ce2f2f207f6acaf5953b5dc6..09b1d752137978581b2ce3d61f14886cb9a82638 100644
--- a/lib/versioning/npm/index.spec.ts
+++ b/lib/versioning/npm/index.spec.ts
@@ -84,6 +84,16 @@ describe('semver.getNewValue()', () => {
       ['^1.2.3', '4.0.0', '^4.0.0'],
       ['^1.2.3', '4.5.6', '^4.0.0'],
       ['^1.0.0', '4.5.6', '^4.0.0'],
+
+      ['^0.2.3', '0.2.4', '^0.2.3'],
+      ['^2.3.0', '2.4.0', '^2.3.0'],
+      ['^2.3.4', '2.4.5', '^2.3.4'],
+      ['^0.0.1', '0.0.2', '^0.0.2'],
+      ['^1.0.1', '2.0.2', '^2.0.0'],
+      ['^1.2.3', '1.2.3', '^1.2.3'],
+      ['^1.2.3', '1.2.2', '^1.2.2'],
+
+      ['^0.9.21', '0.9.22', '^0.9.21'], // #4762
     ].forEach(([currentValue, newVersion, expectedValue]) => {
       expect(
         semver.getNewValue({
diff --git a/lib/versioning/npm/range.ts b/lib/versioning/npm/range.ts
index f3bfbea053b02e03c1206f5261b759866164c383..46cfcfcdcc14bb7fe76b440dbb992886b0692497 100644
--- a/lib/versioning/npm/range.ts
+++ b/lib/versioning/npm/range.ts
@@ -11,6 +11,47 @@ import { parseRange } from 'semver-utils';
 import { logger } from '../../logger';
 import type { NewValueConfig } from '../types';
 
+function replaceCaretValue(oldValue: string, newValue: string): string {
+  const toVersionMajor = major(newValue);
+  const toVersionMinor = minor(newValue);
+  const toVersionPatch = patch(newValue);
+
+  const currentMajor = major(oldValue);
+  const currentMinor = minor(oldValue);
+  const currentPatch = patch(oldValue);
+
+  const oldTuple = [currentMajor, currentMinor, currentPatch];
+  const newTuple = [toVersionMajor, toVersionMinor, toVersionPatch];
+  const resultTuple = [];
+
+  let leadingZero = true;
+  let needReplace = false;
+  for (let idx = 0; idx < 3; idx += 1) {
+    const oldVal = oldTuple[idx];
+    const newVal = newTuple[idx];
+
+    let leadingDigit = false;
+    if (oldVal !== 0 || newVal !== 0) {
+      if (leadingZero) {
+        leadingZero = false;
+        leadingDigit = true;
+      }
+    }
+
+    if (leadingDigit && newVal > oldVal) {
+      needReplace = true;
+    }
+
+    if (!needReplace && newVal < oldVal) {
+      return newValue;
+    }
+
+    resultTuple.push(leadingDigit ? newVal : 0);
+  }
+
+  return needReplace ? resultTuple.join('.') : oldValue;
+}
+
 export function getNewValue({
   currentValue,
   rangeStrategy,
@@ -150,16 +191,7 @@ export function getNewValue({
     if (suffix.length || !currentVersion) {
       return `^${toVersionMajor}.${toVersionMinor}.${toVersionPatch}${suffix}`;
     }
-    if (toVersionMajor === major(currentVersion)) {
-      if (toVersionMajor === 0) {
-        if (toVersionMinor === 0) {
-          return `^${newVersion}`;
-        }
-        return `^${toVersionMajor}.${toVersionMinor}.0`;
-      }
-      return `^${newVersion}`;
-    }
-    return `^${toVersionMajor}.0.0`;
+    return `^${replaceCaretValue(currentVersion, newVersion)}`;
   }
   if (element.operator === '=') {
     return `=${newVersion}`;
diff --git a/lib/versioning/poetry/index.spec.ts b/lib/versioning/poetry/index.spec.ts
index 4779aa3041565564132460d886790658f947ac0d..2b2ee1aa4a52c99d66e40a2ac313a898f8619158 100644
--- a/lib/versioning/poetry/index.spec.ts
+++ b/lib/versioning/poetry/index.spec.ts
@@ -420,9 +420,9 @@ describe(getName(__filename), () => {
           currentValue: '^1.0.0',
           rangeStrategy: 'replace',
           currentVersion: '1.0.0',
-          newVersion: '1.0.7',
+          newVersion: '1.2.3',
         })
-      ).toEqual('^1.0.7');
+      ).toEqual('^1.0.0');
     });
     it('bumps short tilde', () => {
       expect(