diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 07a55593f25a2eb2a8eefe2596e5a388c16f771a..9ad76e41e7b9b6898a3ca13cbaa2f3c9ba288483 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -1881,6 +1881,7 @@ This way Renovate can use GitHub's [Commit signing support for bots and other Gi
 
 ## postUpdateOptions
 
+- `gomodNoMassage`: Skip massaging `replace` directives before calling `go` commands
 - `gomodTidy`: Run `go mod tidy` after Go module updates. This is implicitly enabled for major module updates when `gomodUpdateImportPaths` is enabled
 - `gomodTidy1.17`: Run `go mod tidy -compat=1.17` after Go module updates.
 - `gomodUpdateImportPaths`: Update source import paths on major module updates, using [mod](https://github.com/marwan-at-work/mod)
diff --git a/docs/usage/golang.md b/docs/usage/golang.md
index f450e05c1fa7f70b3a88bcb47a0728d411c3a499..9519ab48225ec3457b3cc6f5234c82c04473d7d4 100644
--- a/docs/usage/golang.md
+++ b/docs/usage/golang.md
@@ -28,6 +28,15 @@ To install Renovate Bot itself, either enable the [Renovate App](https://github.
 
 ## Technical Details
 
+### Replace massaging
+
+Renovate's default behavior is to massage any `replace` statements it finds prior to running `go` commands, and then massage them back afterwards.
+This was originally done because relative `replace` statements outside of the current repo will not work when Renovate clones the repo locally.
+
+On the other hand, this massaging of `replace` statements may lead to unexpected results, especially because `go mod tidy` may not fully tidy the `go.sum` if it is missing the `replace` directives in `go.mod`.
+
+To disable this default behavior, and retain all `replace` statements when running `go` commands, add `gomodNoMassage` to your `postUpdateOptions` array.
+
 ### Module Tidying
 
 Go Modules tidying is not enabled by default, and is opt-in via the [`postUpdateOptions`](https://docs.renovatebot.com/configuration-options/#postupdateoptions) config option.
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index 6948d502b5a3f6eaf5bbba2d50c82a8425c43252..623b11fd5d50ef2c1bcac517719e560e57a3d3f4 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -1820,6 +1820,7 @@ const options: RenovateOptions[] = [
     type: 'array',
     default: [],
     allowedValues: [
+      'gomodNoMassage',
       'gomodUpdateImportPaths',
       'gomodTidy',
       'gomodTidy1.17',
diff --git a/lib/modules/manager/gomod/artifacts.ts b/lib/modules/manager/gomod/artifacts.ts
index 00630808719d8ea6413b3f21154e41f84f13bbaa..00722db7e8385b0b2d8c5ce9470b52a628a30730 100644
--- a/lib/modules/manager/gomod/artifacts.ts
+++ b/lib/modules/manager/gomod/artifacts.ts
@@ -158,7 +158,9 @@ export async function updateArtifacts({
   const vendorModulesFileName = upath.join(vendorDir, 'modules.txt');
   const useVendor = (await readLocalFile(vendorModulesFileName)) !== null;
 
-  try {
+  let massagedGoMod = newGoModContent;
+
+  if (!config.postUpdateOptions?.includes('gomodNoMassage')) {
     // Regex match inline replace directive, example:
     // replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5
     // https://go.dev/ref/mod#go-mod-file-replace
@@ -186,13 +188,15 @@ export async function updateArtifacts({
       match.replace(/(\r?\n)/g, '$1// renovate-replace ');
 
     // Comment out golang replace directives
-    const massagedGoMod = newGoModContent
+    massagedGoMod = newGoModContent
       .replace(inlineReplaceRegEx, inlineCommentOut)
       .replace(blockReplaceRegEx, blockCommentOut);
 
     if (massagedGoMod !== newGoModContent) {
       logger.debug('Removed some relative replace statements from go.mod');
     }
+  }
+  try {
     await writeLocalFile(goModFileName, massagedGoMod);
 
     const cmd = 'go';
diff --git a/lib/modules/manager/gomod/readme.md b/lib/modules/manager/gomod/readme.md
index b749e7bba52d192a34098e08caa587fe57b6bf77..0610e6bdf7b5707e55636dc879a5c84a1afbaf49 100644
--- a/lib/modules/manager/gomod/readme.md
+++ b/lib/modules/manager/gomod/readme.md
@@ -4,6 +4,7 @@ You might be interested in the following `postUpdateOptions`:
    1. This is implicitly enabled for major updates if the user has enabled the option `gomodUpdateImportPaths`
 1. `gomodTidy1.17` - if you'd like Renovate to run `go mod tidy -compat=1.17` after every update before raising the PR.
 1. `gomodUpdateImportPaths` - if you'd like Renovate to update your source import paths on major updates before raising the PR.
+1. `gomodNoMassage` - to skip massaging of `replace` statements.
 
 When Renovate is running using `binarySource=docker` (such as in the hosted WhiteSource Renovate app) then it will pick the latest compatible version of Go to run, i.e. the latest `1.x` release.
 Therefore even if the `go.mod` has a version like `go 1.14`, you will see Renovate treating that as a `^1.14` constraint and not `=1.14`.