diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c
index 7d8ada39e96..97d4b2f2bac 100644
--- a/gdb/debuginfod-support.c
+++ b/gdb/debuginfod-support.c
@@ -38,6 +38,8 @@ static cmd_list_element *maint_show_debuginfod_cmdlist;
 static const char debuginfod_on[] = "on";
 static const char debuginfod_off[] = "off";
 static const char debuginfod_ask[] = "ask";
+static const char debuginfod_one[] = "one";
+static const char debuginfod_all[] = "all";
 
 static const char *debuginfod_enabled_enum[] =
 {
@@ -47,6 +49,20 @@ static const char *debuginfod_enabled_enum[] =
   nullptr
 };
 
+/* Valid values for set debuginfod cancel command.  */
+
+static const char *debuginfod_cancel_enum[] =
+{
+  debuginfod_one,
+  debuginfod_all,
+  debuginfod_ask,
+  nullptr
+};
+
+/* Value of debuginfod cancellation mode.  */
+
+static const char *debuginfod_cancel = debuginfod_ask;
+
 static const char *debuginfod_enabled =
 #if defined(HAVE_LIBDEBUGINFOD)
   debuginfod_ask;
@@ -109,9 +125,11 @@ debuginfod_section_query (const unsigned char *build_id,
 struct user_data
 {
   user_data (const char *desc, const char *fname)
-    : desc (desc), fname (fname)
+    : pass_quit_flag (false), inf_had_term (false), desc (desc), fname (fname)
   { }
 
+  bool pass_quit_flag;
+  bool inf_had_term;
   const char * const desc;
   const char * const fname;
   ui_out::progress_update progress;
@@ -156,10 +174,83 @@ progressfn (debuginfod_client *c, long cur, long total)
   if (check_quit_flag ())
     {
       ui_file *outstream = get_unbuffered (gdb_stdout);
-      gdb_printf (outstream, _("Cancelling download of %s %s...\n"),
-		  data->desc, styled_fname.c_str ());
-      return 1;
-    }
+
+      /* If a single Ctrl-C occurs during downloading, let it propagate to the
+	 target.  If more than one Ctrl-C occurs, ask whether to cancel the
+	 current download or interrupt the target.  If the download is
+	 cancelled, the setting of debuginfod_cancel will determine whether
+	 the current download is cancelled or debuginfod is disabled.  */
+      if (!data->pass_quit_flag)
+	data->pass_quit_flag = true;
+      else
+	{
+	  int resp = 1;
+	  bool extra_nl = false;
+
+	  if (data->inf_had_term)
+	    {
+	      /* If Ctrl-C occurs during the following prompts, catch the
+		 exception to prevent unsafe early returns to gdb's main
+		 event loop.  During these prompts, Ctrl-C is equivalent to
+		 answering 'y'.  */
+	      try
+		{
+		  resp = yquery (_("Cancel the current download?\nIf no, "
+				   "then Ctrl-C will be sent to the target "
+				   "process. "));
+		}
+	      catch (const gdb_exception &)
+		{
+		  /* If the query doesn't complete, then we need an additional
+		     newline to get "Cancelling download of..." printed on a
+		     separate line.  */
+		  extra_nl = true;
+		}
+	    }
+	  if (resp)
+	    {
+	      if (extra_nl)
+		{
+		  gdb_printf (outstream, "\n");
+		  extra_nl = false;
+		}
+
+	      gdb_printf (outstream, _("Cancelling download of %s %s...\n"),
+				       data->desc, styled_fname.c_str ());
+	      if (debuginfod_cancel == debuginfod_ask)
+		{
+		  try
+		    {
+		      resp = nquery
+			(_("Cancel further downloading for this session? "));
+		    }
+		  catch (const gdb_exception &)
+		    {
+		      resp = 1;
+		      extra_nl = true;
+		    }
+
+		  if (resp)
+		    debuginfod_cancel = debuginfod_all;
+		  else
+		    debuginfod_cancel = debuginfod_one;
+		}
+	      if (debuginfod_cancel == debuginfod_all)
+		{
+		  if (extra_nl)
+		    gdb_printf (outstream, "\n");
+
+		  gdb_printf (outstream,
+			      _("Debuginfod has been disabled.\nTo re-enable "
+				"use the 'set debuginfod enabled' command.\n"));
+		  debuginfod_enabled = debuginfod_off;
+		}
+
+	    data->pass_quit_flag = false;
+	    return 1;
+	  }
+      }
+  }
 
   if (debuginfod_verbose == 0)
     return 0;
@@ -330,6 +421,10 @@ debuginfod_source_query (const unsigned char *build_id,
     user_data data ("source file", srcpath);
 
     debuginfod_set_user_data (c, &data);
+
+   if (!target_terminal::is_ours ())
+     data.inf_had_term = true;
+
     if (target_supports_terminal_ours ())
       {
 	term_state.emplace ();
@@ -341,6 +436,11 @@ debuginfod_source_query (const unsigned char *build_id,
 					    build_id_len,
 					    srcpath,
 					    &dname));
+    if (data.pass_quit_flag)
+      set_quit_flag ();
+    if (data.inf_had_term && term_state.has_value ())
+      target_terminal::inferior ();
+
     debuginfod_set_user_data (c, nullptr);
   }
 
@@ -376,6 +476,10 @@ debuginfod_debuginfo_query (const unsigned char *build_id,
     user_data data ("separate debug info for", filename);
 
     debuginfod_set_user_data (c, &data);
+
+    if (!target_terminal::is_ours ())
+      data.inf_had_term = true;
+
     if (target_supports_terminal_ours ())
       {
 	term_state.emplace ();
@@ -384,6 +488,12 @@ debuginfod_debuginfo_query (const unsigned char *build_id,
 
     fd = scoped_fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
 					       &dname));
+
+    if (data.pass_quit_flag)
+      set_quit_flag ();
+    if (data.inf_had_term && term_state.has_value ())
+      target_terminal::inferior ();
+
     debuginfod_set_user_data (c, nullptr);
   }
 
@@ -419,6 +529,10 @@ debuginfod_exec_query (const unsigned char *build_id,
     user_data data ("executable for", filename);
 
     debuginfod_set_user_data (c, &data);
+
+    if (!target_terminal::is_ours ())
+      data.inf_had_term = true;
+
     if (target_supports_terminal_ours ())
       {
 	term_state.emplace ();
@@ -427,6 +541,11 @@ debuginfod_exec_query (const unsigned char *build_id,
 
     fd = scoped_fd (debuginfod_find_executable (c, build_id, build_id_len,
 						&dname));
+    if (data.pass_quit_flag)
+      set_quit_flag ();
+    if (data.inf_had_term && term_state.has_value ())
+      target_terminal::inferior ();
+
     debuginfod_set_user_data (c, nullptr);
   }
 
@@ -467,6 +586,10 @@ debuginfod_section_query (const unsigned char *build_id,
   {
     user_data data (desc.c_str (), filename);
     debuginfod_set_user_data (c, &data);
+
+    if (!target_terminal::is_ours ())
+      data.inf_had_term = true;
+
     if (target_supports_terminal_ours ())
       {
 	term_state.emplace ();
@@ -475,6 +598,12 @@ debuginfod_section_query (const unsigned char *build_id,
 
     fd = scoped_fd (debuginfod_find_section (c, build_id, build_id_len,
 					     section_name, &dname));
+
+    if (data.pass_quit_flag)
+      set_quit_flag ();
+    if (data.inf_had_term && term_state.has_value ())
+      target_terminal::inferior ();
+
     debuginfod_set_user_data (c, nullptr);
   }
 
@@ -523,6 +652,33 @@ show_debuginfod_enabled (ui_file *file, int from_tty, cmd_list_element *cmd,
 		"\"%s\".\n"), debuginfod_enabled);
 }
 
+/* Set callback for "set debuginfod cancel".  */
+
+static void
+set_debuginfod_cancel (const char *value)
+{
+  debuginfod_cancel = value;
+}
+
+/* Get callback for "set debuginfod cancel".  */
+
+static const char *
+get_debuginfod_cancel ()
+{
+  return debuginfod_cancel;
+}
+
+/* Show callback for "set debuginfod cancel".  */
+
+static void
+show_debuginfod_cancel (ui_file *file, int from_tty, cmd_list_element *cmd,
+			const char *value)
+{
+  gdb_printf (file,
+	      _("Debuginfod cancellation mode is currently set to "
+		"\"%s\".\n"), debuginfod_cancel);
+}
+
 /* Set callback for "set debuginfod urls".  */
 
 static void
@@ -627,6 +783,23 @@ When set to \"ask\", prompt whether to enable or disable debuginfod." ),
 			&set_debuginfod_prefix_list,
 			&show_debuginfod_prefix_list);
 
+  add_setshow_enum_cmd ("cancel", class_run, debuginfod_cancel_enum,
+			_("Set Ctrl-C behaviour for debuginfod."),
+			_("Show Ctrl-C behaviour for debuginfod."),
+			_("\
+When set to \'one\', pressing Ctrl-C twice cancels a single \
+download.\nWhen set to \'all\', pressing Ctrl-C twice cancels all further downloads.\n\
+When set to \'ask\', pressing Ctrl-C twice asks what to do.\nA single Ctrl-C during \
+downloading is passed to the target process being debugged.\nA second Ctrl-C \
+during downloading may raise a prompt asking whether to cancel the download or \
+send Ctrl-C to the target.\nIf the download is cancelled, then no Ctrl-C is \
+sent to the target."),
+			set_debuginfod_cancel,
+			get_debuginfod_cancel,
+			show_debuginfod_cancel,
+			&set_debuginfod_prefix_list,
+			&show_debuginfod_prefix_list);
+
   /* set/show debuginfod urls */
   add_setshow_string_noescape_cmd ("urls", class_run, _("\
 Set the list of debuginfod server URLs."), _("\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e98c15242bc..d6df28896b1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -50259,6 +50259,27 @@ is set to @code{ask} for interactive sessions.
 Display whether @code{debuginfod enabled} is set to @code{on}, @code{off} or
 @code{ask}.
 
+@kindex set debuginfod cancel
+@anchor{set debuginfod cancel}
+@item set debuginfod cancel
+@itemx set debuginfod cancel one
+@cindex debuginfod @kbd{Ctrl-C} behaviour
+Pressing @kbd{Ctrl-C} twice during downloading will cancel the current
+download.
+
+@item set debuginfod cancel all
+Pressing @kbd{Ctrl-C} twice during downloading will cancel this and all
+further downloads.
+
+@item set debuginfod cancel ask
+Pressing @kbd{Ctrl-C} twice during downloading will cancel the current
+download and prompt whether to cancel all further downloads.  By default,
+@code{debuginfod cancel} is set to @code{ask} for interactive sessions.
+
+@kindex show debuginfod cancel
+@item show debuginfod cancel
+Display the current setting of @code{debuginfod cancel}.
+
 @kindex set debuginfod urls
 @cindex configure debuginfod URLs
 @item set debuginfod urls
