diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index ecdaae3..370283a 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -60,6 +60,7 @@ vte_terminal_match_check
 vte_terminal_match_check_event
 vte_terminal_match_set_cursor_type
 vte_terminal_match_set_cursor_name
+vte_terminal_match_set_underline
 vte_terminal_set_cjk_ambiguous_width
 vte_terminal_get_cjk_ambiguous_width
 vte_terminal_set_encoding
diff --git a/src/vte.cc b/src/vte.cc
index 014edd2..6af3188 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -1217,6 +1217,10 @@ vte_terminal_set_cursor_from_regex_match(VteTerminal *terminal, struct vte_match
 
         if (cursor)
                 g_object_unref(cursor);
+
+        /* This doesn't strictly speaking belong here, but we piggyback on the cursor
+         * to set whether the matching string should be underlined on mouseover. */
+        terminal->pvt->match_underline = regex->underline;
 }
 
 /**
@@ -1354,6 +1358,7 @@ vte_terminal_match_add_gregex(VteTerminal *terminal,
         new_regex_match.regex.gregex.match_flags = gflags;
         new_regex_match.cursor_mode = VTE_REGEX_CURSOR_GDKCURSORTYPE;
         new_regex_match.cursor.cursor_type = VTE_DEFAULT_CURSOR;
+        new_regex_match.underline = TRUE;
 
         return vte_terminal_match_add_internal(terminal, &new_regex_match);
 }
@@ -1391,6 +1396,7 @@ vte_terminal_match_add_regex(VteTerminal *terminal,
         new_regex_match.regex.pcre.match_flags = flags;
         new_regex_match.cursor_mode = VTE_REGEX_CURSOR_GDKCURSORTYPE;
         new_regex_match.cursor.cursor_type = VTE_DEFAULT_CURSOR;
+        new_regex_match.underline = TRUE;
 
         return vte_terminal_match_add_internal(terminal, &new_regex_match);
 }
@@ -1473,6 +1479,31 @@ vte_terminal_match_set_cursor_name(VteTerminal *terminal,
 	vte_terminal_match_hilite_clear(terminal);
 }
 
+/**
+ * vte_terminal_match_set_underline:
+ * @terminal: a #VteTerminal
+ * @tag: the tag of the regex which should use the specified underline
+ * @underline: whether to enable underlining
+ *
+ * Sets whether the match should be underlined if the pointer is over the
+ * pattern specified by @tag.
+ *
+ * Since: 0.44
+ */
+void
+vte_terminal_match_set_underline(VteTerminal *terminal,
+				 int tag, gboolean underline)
+{
+        struct vte_match_regex *regex;
+        g_return_if_fail(VTE_IS_TERMINAL(terminal));
+        g_return_if_fail((guint) tag < terminal->pvt->match_regexes->len);
+        regex = &g_array_index(terminal->pvt->match_regexes,
+                               struct vte_match_regex,
+                               tag);
+        regex->underline = underline;
+        vte_terminal_match_hilite_clear(terminal);
+}
+
 #ifdef WITH_PCRE2
 
 /* creates a pcre match context with appropriate limits */
@@ -6285,7 +6316,7 @@ vte_terminal_match_hilite_update(VteTerminal *terminal, long x, long y)
 						  &terminal->pvt->match_tag,
 						  &start,
 						  &end);
-	if (terminal->pvt->show_match) {
+	if (terminal->pvt->show_match && terminal->pvt->match_underline) {
 		/* Repaint what used to be hilited, if anything. */
 		_vte_invalidate_region(terminal,
 				terminal->pvt->match_start.col,
@@ -10141,7 +10172,7 @@ vte_terminal_draw_rows(VteTerminal *terminal,
 			strikethrough = cell->attr.strikethrough;
 			bold = cell->attr.bold;
 			italic = cell->attr.italic;
-			if (terminal->pvt->show_match) {
+			if (terminal->pvt->show_match && terminal->pvt->match_underline) {
 				hilite = vte_cell_is_between(i, row,
 						terminal->pvt->match_start.col,
 						terminal->pvt->match_start.row,
@@ -10212,7 +10243,7 @@ vte_terminal_draw_rows(VteTerminal *terminal,
 					}
 					/* Break up matched/not-matched text. */
 					nhilite = FALSE;
-					if (terminal->pvt->show_match) {
+					if (terminal->pvt->show_match && terminal->pvt->match_underline) {
 						nhilite = vte_cell_is_between(j, row,
 								terminal->pvt->match_start.col,
 								terminal->pvt->match_start.row,
@@ -10480,7 +10511,7 @@ vte_terminal_paint_cursor(VteTerminal *terminal)
 							     x, y,
 							     cursor_width, height);
 
-                                if (cell && terminal->pvt->show_match) {
+                                if (cell && terminal->pvt->show_match && terminal->pvt->match_underline) {
                                         hilite = vte_cell_is_between(col, row,
                                                         terminal->pvt->match_start.col,
                                                         terminal->pvt->match_start.row,
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 8f8a1e5..48b4c15 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -300,6 +300,9 @@ void vte_terminal_match_set_cursor_type(VteTerminal *terminal,
 void vte_terminal_match_set_cursor_name(VteTerminal *terminal,
 					int tag,
                                         const char *cursor_name) _VTE_GNUC_NONNULL(1) _VTE_GNUC_NONNULL(3);
+void vte_terminal_match_set_underline(VteTerminal *terminal,
+                                      int tag,
+                                      gboolean underline) _VTE_GNUC_NONNULL(1);
 void vte_terminal_match_remove(VteTerminal *terminal,
                                int tag) _VTE_GNUC_NONNULL(1);
 void vte_terminal_match_remove_all(VteTerminal *terminal) _VTE_GNUC_NONNULL(1);
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 9175b8f..f25a1b2 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -66,6 +66,7 @@ struct vte_match_regex {
                char *cursor_name;
                GdkCursorType cursor_type;
         } cursor;
+        gboolean underline;
 };
 
 typedef enum _VteCharacterReplacement {
@@ -340,6 +341,7 @@ public:
 	char *match;
 	int match_tag;
 	VteVisualPosition match_start, match_end;
+        gboolean match_underline;
 	gboolean show_match;
 
 	/* Search data. */
