diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index a4345e0fed..b1af34ca07 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -20,7 +20,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
 * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): set `up` metric to `0` for partial scrapes in [stream parsing mode](https://docs.victoriametrics.com/vmagent.html#stream-parsing-mode). Previously the `up` metric was set to `1` when at least a single metric has been scraped before the error. This aligns the behaviour of `vmselect` with Prometheus.
 * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): restart all the scrape jobs during [config reload](https://docs.victoriametrics.com/vmagent.html#configuration-update) after `global` section is changed inside `-promscrape.config`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2884).
 * BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly assume role with AWS ECS credentials. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2875). Thanks to @transacid for [the fix](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2876).
-
+* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): do not split regex in [relabeling rules](https://docs.victoriametrics.com/vmagent.html#relabeling) into multiple lines if it contains groups. This fixes [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2928).
 
 
 ## [v1.79.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.79.1)
diff --git a/lib/promrelabel/config.go b/lib/promrelabel/config.go
index c25813e224..830cf7cfeb 100644
--- a/lib/promrelabel/config.go
+++ b/lib/promrelabel/config.go
@@ -104,6 +104,11 @@ func stringValue(v interface{}) (string, error) {
 
 // MarshalYAML marshals mlr to YAML.
 func (mlr *MultiLineRegex) MarshalYAML() (interface{}, error) {
+	if strings.ContainsAny(mlr.S, "([") {
+		// The mlr.S contains groups. Fall back to returning the regexp as is without splitting it into parts.
+		// This fixes https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2928 .
+		return mlr.S, nil
+	}
 	a := strings.Split(mlr.S, "|")
 	if len(a) == 1 {
 		return a[0], nil
diff --git a/lib/promrelabel/config_test.go b/lib/promrelabel/config_test.go
index bdf343d822..24bd4f7316 100644
--- a/lib/promrelabel/config_test.go
+++ b/lib/promrelabel/config_test.go
@@ -7,6 +7,30 @@ import (
 	"gopkg.in/yaml.v2"
 )
 
+func TestMultiLineRegexUnmarshalMarshal(t *testing.T) {
+	f := func(data, resultExpected string) {
+		t.Helper()
+		var mlr MultiLineRegex
+		if err := yaml.UnmarshalStrict([]byte(data), &mlr); err != nil {
+			t.Fatalf("cannot unmarshal %q: %s", data, err)
+		}
+		result, err := yaml.Marshal(&mlr)
+		if err != nil {
+			t.Fatalf("cannot marshal %q: %s", data, err)
+		}
+		if string(result) != resultExpected {
+			t.Fatalf("unexpected marshaled data; got\n%q\nwant\n%q", result, resultExpected)
+		}
+	}
+	f(``, `""`+"\n")
+	f(`foo`, "foo\n")
+	f(`a|b||c`, "- a\n- b\n- \"\"\n- c\n")
+	f(`(a|b)`, "(a|b)\n")
+	f(`a|b[c|d]`, "a|b[c|d]\n")
+	f("- a\n- b", "- a\n- b\n")
+	f("- a\n- (b)", "a|(b)\n")
+}
+
 func TestRelabelConfigMarshalUnmarshal(t *testing.T) {
 	f := func(data, resultExpected string) {
 		t.Helper()