diff --git a/gdb/NEWS b/gdb/NEWS
index 1567cbea9bd..89b9d32817a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -44,6 +44,12 @@
   keyword already gave an error when used multiple times with the
   watch command, this remains unchanged.
 
+* For both the break and watch commands, it is now invalid to use both
+  the 'thread' and 'task' keywords within the same command.  For
+  example the following commnds will now give an error:
+    break foo thread 1 task 1
+    watch var thread 2 task 3
+
 * New commands
 
 maintenance print record-instruction [ N ]
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index adf38e7d722..8963b10d516 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1454,12 +1454,16 @@ breakpoint_set_silent (struct breakpoint *b, int silent)
     gdb::observers::breakpoint_modified.notify (b);
 }
 
-/* Set the thread for this breakpoint.  If THREAD is -1, make the
-   breakpoint work for any thread.  */
+/* See breakpoint.h.  */
 
 void
 breakpoint_set_thread (struct breakpoint *b, int thread)
 {
+  /* It is invalid to set the thread field to anything other than -1 (which
+     means no thread restriction) if a task restriction is already in
+     place.  */
+  gdb_assert (thread == -1 || b->task == 0);
+
   int old_thread = b->thread;
 
   b->thread = thread;
@@ -1467,12 +1471,16 @@ breakpoint_set_thread (struct breakpoint *b, int thread)
     gdb::observers::breakpoint_modified.notify (b);
 }
 
-/* Set the task for this breakpoint.  If TASK is 0, make the
-   breakpoint work for any task.  */
+/* See breakpoint.h.  */
 
 void
 breakpoint_set_task (struct breakpoint *b, int task)
 {
+  /* It is invalid to set the task field to anything other than 0 (which
+     means no task restriction) if a thread restriction is already in
+     place.  */
+  gdb_assert (task == 0 || b->thread == -1);
+
   int old_task = b->task;
 
   b->task = task;
@@ -8438,6 +8446,8 @@ code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_,
 
   gdb_assert (!sals.empty ());
 
+  /* At most one of thread or task can be set on any breakpoint.  */
+  gdb_assert (thread == -1 || task == 0);
   thread = thread_;
   task = task_;
 
@@ -8806,6 +8816,9 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 	  if (*thread != -1)
 	    error(_("You can specify only one thread."));
 
+	  if (*task != 0)
+	    error (_("You can specify only one of thread or task."));
+
 	  tok = end_tok + 1;
 	  thr = parse_thread_id (tok, &tmptok);
 	  if (tok == tmptok)
@@ -8820,6 +8833,9 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 	  if (*task != 0)
 	    error(_("You can specify only one task."));
 
+	  if (*thread != -1)
+	    error (_("You can specify only one of thread or task."));
+
 	  tok = end_tok + 1;
 	  *task = strtol (tok, &tmptok, 0);
 	  if (tok == tmptok)
@@ -8854,7 +8870,7 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
   for (auto &sal : sals)
     {
       gdb::unique_xmalloc_ptr<char> cond;
-      int thread_id = 0;
+      int thread_id = -1;
       int task_id = 0;
       gdb::unique_xmalloc_ptr<char> remaining;
 
@@ -8869,6 +8885,8 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
 	  find_condition_and_thread (input, sal.pc, &cond, &thread_id,
 				     &task_id, &remaining);
 	  *cond_string = std::move (cond);
+	  /* At most one of thread or task can be set.  */
+	  gdb_assert (thread_id == -1 || task_id == 0);
 	  *thread = thread_id;
 	  *task = task_id;
 	  *rest = std::move (remaining);
@@ -10089,6 +10107,9 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 	      if (thread != -1)
 		error(_("You can specify only one thread."));
 
+	      if (task != 0)
+		error (_("You can specify only one of thread or task."));
+
 	      /* Extract the thread ID from the next token.  */
 	      thr = parse_thread_id (value_start, &endp);
 
@@ -10105,6 +10126,9 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 	      if (task != 0)
 		error(_("You can specify only one task."));
 
+	      if (thread != -1)
+		error (_("You can specify only one of thread or task."));
+
 	      task = strtol (value_start, &tmp, 0);
 	      if (tmp == value_start)
 		error (_("Junk after task keyword."));
@@ -10280,6 +10304,8 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   else
     w.reset (new watchpoint (nullptr, bp_type));
 
+  /* At most one of thread or task can be set on a watchpoint.  */
+  gdb_assert (thread == -1 || task == 0);
   w->thread = thread;
   w->task = task;
   w->disposition = disp_donttouch;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 352e8468537..5228c38fe02 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1673,8 +1673,18 @@ extern void breakpoint_set_commands (struct breakpoint *b,
 
 extern void breakpoint_set_silent (struct breakpoint *b, int silent);
 
+/* Set the thread for this breakpoint.  If THREAD is -1, make the
+   breakpoint work for any thread.  Passing a value other than -1 for
+   THREAD should only be done if b->task is 0; it is not valid to try and
+   set both a thread and task restriction on a breakpoint.  */
+
 extern void breakpoint_set_thread (struct breakpoint *b, int thread);
 
+/* Set the task for this breakpoint.  If TASK is 0, make the breakpoint
+   work for any task.  Passing a value other than 0 for TASK should only be
+   done if b->thread is -1; it is not valid to try and set both a thread
+   and task restriction on a breakpoint.  */
+
 extern void breakpoint_set_task (struct breakpoint *b, int task);
 
 /* Clear the "inserted" flag in all breakpoints.  */
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index a7e043d847b..d4f2b7310bd 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -773,6 +773,11 @@ gdbscm_set_breakpoint_thread_x (SCM self, SCM newvalue)
 	  gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
 				     _("invalid thread id"));
 	}
+
+      if (bp_smob->bp->task != 0)
+	scm_misc_error (FUNC_NAME,
+			_("cannot set both task and thread attributes"),
+			SCM_EOL);
     }
   else if (gdbscm_is_false (newvalue))
     id = -1;
@@ -828,6 +833,11 @@ gdbscm_set_breakpoint_task_x (SCM self, SCM newvalue)
 	  gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
 				     _("invalid task id"));
 	}
+
+      if (bp_smob->bp->thread != -1)
+	scm_misc_error (FUNC_NAME,
+			_("cannot set both task and thread attributes"),
+			SCM_EOL);
     }
   else if (gdbscm_is_false (newvalue))
     id = 0;
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 1b10ccd5415..52298935242 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -270,6 +270,13 @@ bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
 			   _("Invalid thread ID."));
 	  return -1;
 	}
+
+      if (self_bp->bp->task != 0)
+	{
+	  PyErr_SetString (PyExc_RuntimeError,
+			   _("Cannot set both task and thread attributes."));
+	  return -1;
+	}
     }
   else if (newvalue == Py_None)
     id = -1;
@@ -321,6 +328,13 @@ bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
 			   _("Invalid task ID."));
 	  return -1;
 	}
+
+      if (self_bp->bp->thread != -1)
+	{
+	  PyErr_SetString (PyExc_RuntimeError,
+			   _("Cannot set both task and thread attributes."));
+	  return -1;
+	}
     }
   else if (newvalue == Py_None)
     id = 0;
diff --git a/gdb/testsuite/gdb.ada/tasks.exp b/gdb/testsuite/gdb.ada/tasks.exp
index 88ef123865b..9d4f396e88e 100644
--- a/gdb/testsuite/gdb.ada/tasks.exp
+++ b/gdb/testsuite/gdb.ada/tasks.exp
@@ -14,6 +14,8 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 load_lib "ada.exp"
+load_lib "gdb-guile.exp"
+load_lib "gdb-python.exp"
 
 require allow_ada_tests
 
@@ -39,17 +41,35 @@ gdb_test "info tasks" \
                "\r\n"] \
          "info tasks before inserting breakpoint"
 
+# Confirm that the "info threads" output lines up with the tasks list.
+gdb_test "info threads" \
+    [multi_line \
+	 "\\*\\s+1\\s+\[^\r\n\]+\\s\"foo\"\\s\[^\r\n\]+" \
+	 "\\s+2\\s+\[^\r\n\]+\\s\"task_list\\(1\\)\"\\s\[^\r\n\]+" \
+	 "\\s+3\\s+\[^\r\n\]+\\s\"task_list\\(2\\)\"\\s\[^\r\n\]+" \
+	 "\\s+4\\s+\[^\r\n\]+\\s\"task_list\\(3\\)\"\\s\[^\r\n\]+"]
+
 # Check that multiple uses of the 'task' keyword will give an error.
 gdb_test "break break_me task 1 task 3" "You can specify only one task\\."
 gdb_test "watch j task 1 task 3" "You can specify only one task\\."
 
+# Check that attempting to combine 'task' and 'thread' gives an error.
+gdb_test "break break_me task 1 thread 1" \
+    "You can specify only one of thread or task\\."
+gdb_test "break break_me thread 1 task 1" \
+    "You can specify only one of thread or task\\."
+gdb_test "watch j task 1 thread 1" \
+    "You can specify only one of thread or task\\."
+gdb_test "watch j thread 1 task 1" \
+    "You can specify only one of thread or task\\."
+
 # Insert a breakpoint that should stop only if task 1 stops.  Since
 # task 1 never calls break_me, this shouldn't actually ever trigger.
 # The fact that this breakpoint is created _before_ the next one
 # matters.  GDB used to have a bug where it would report the first
 # breakpoint in the list that matched the triggered-breakpoint's
 # address, no matter which task it was specific to.
-gdb_test "break break_me task 1" "Breakpoint .* at .*"
+gdb_breakpoint "break_me task 1" message
 gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
     "check info breakpoints for task 1 breakpoint"
 
@@ -57,8 +77,67 @@ gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
 # extract its number.
 gdb_breakpoint "break_me task 3" message
 set bp_number [get_integer_valueof "\$bpnum" -1]
-if {$bp_number < 0} {
-    return
+gdb_assert { $bp_number > 0 } "check for a valid breakpoint number"
+
+# Test the Python API for the breakpoint task attribute.
+if {[allow_python_tests]} {
+    gdb_test_no_output "python bp = gdb.breakpoints()\[$bp_number - 1\]"
+    gdb_test "python print(bp.task)" "3"
+    gdb_test "python print(bp.thread)" "None"
+    gdb_test "python bp.thread = 1" \
+	[multi_line \
+	     "RuntimeError: Cannot set both task and thread attributes\\." \
+	     "Error while executing Python code\\."] \
+	"try setting the thread, but expect an error"
+    gdb_test_no_output "python bp.task = None"
+    gdb_test_no_output "python bp.thread = 1"
+    gdb_test "python bp.task = 3" \
+	[multi_line \
+	     "RuntimeError: Cannot set both task and thread attributes\\." \
+	     "Error while executing Python code\\."] \
+	"try setting the task, but expect an error"
+
+    # Reset the breakpoint to the state required for the rest of this
+    # test.
+    gdb_test_no_output "python bp.thread = None"
+    gdb_test_no_output "python bp.task = 3"
+}
+
+# Test the Guile API for the breakpoint task attribute.
+if {[allow_guile_tests]} {
+    gdb_install_guile_utils
+    gdb_install_guile_module
+
+    gdb_scm_test_silent_cmd "guile (define blist (breakpoints))" \
+	"get breakpoint list"
+    gdb_scm_test_silent_cmd "guile (define bp (list-ref blist (- $bp_number 1)))" \
+	"get breakpoint from list"
+    gdb_test "guile (print (breakpoint-task bp))" "= 3"
+    gdb_test "guile (print (breakpoint-thread bp))" "= #f"
+    gdb_test "guile (set-breakpoint-thread! bp 1)" \
+	[multi_line \
+	     "ERROR: In procedure set-breakpoint-thread!:" \
+	     "In procedure gdbscm_set_breakpoint_thread_x: cannot set both task and thread attributes" \
+	     "Error while executing Scheme code."] \
+	"attempt to set thread, but expect an error"
+
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-task! bp #f)" \
+	"clear breakpoint task attribute"
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-thread! bp 1)" \
+	"set breakpoint thread now task is unset"
+    gdb_test "guile (set-breakpoint-task! bp 1)" \
+	[multi_line \
+	     "ERROR: In procedure set-breakpoint-task!:" \
+	     "In procedure gdbscm_set_breakpoint_task_x: cannot set both task and thread attributes" \
+	     "Error while executing Scheme code."] \
+	"attempt to set task, but expect an error"
+
+    # Reset the breakpoint to the state required for the rest of this
+    # test.
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-thread! bp #f)" \
+	"clear breakpoint thread attribute"
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-task! bp 3)" \
+	"restore breakpoint task attribute"
 }
 gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 3" \
     "check info breakpoints for task 3 breakpoint"
