diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 67882d0cd89..778bc79b1b3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -25276,7 +25276,7 @@
 @cindex history file
 @kindex set history filename
 @cindex @env{GDBHISTFILE}, environment variable
-@item set history filename @var{fname}
+@item set history filename @r{[}@var{fname}@r{]}
 Set the name of the @value{GDBN} command history file to @var{fname}.
 This is the file where @value{GDBN} reads an initial command history
 list, and where it writes the command history from this session when it
@@ -25286,15 +25286,27 @@
 @file{./.gdb_history} (@file{./_gdb_history} on MS-DOS) if this variable
 is not set.
 
+The @code{GDBHISTFILE} environment variable is read after processing
+any @value{GDBN} initialization files (@xref{Startup}) and after
+processing any commands passed using command line options (for
+example, @code{-ex}).
+
+If the @var{fname} argument is not given, or if the @code{GDBHISTFILE}
+is the empty string then @value{GDBN} will neither try to load an
+existing history file, nor will it try to save the history on exit.
+
 @cindex save command history
 @kindex set history save
 @item set history save
 @itemx set history save on
 Record command history in a file, whose name may be specified with the
-@code{set history filename} command.  By default, this option is disabled.
+@code{set history filename} command.  By default, this option is
+disabled.  The command history will be recorded when @value{GDBN}
+exits.
 
 @item set history save off
-Stop recording command history in a file.
+Don't record the command history into the file specified by @code{set
+history filename} when @value{GDBN} exits.
 
 @cindex history size
 @kindex set history size
@@ -25308,6 +25320,11 @@
 either a negative number or the empty string, then the number of commands
 @value{GDBN} keeps in the history list is unlimited.
 
+The @code{GDBHISTSIZE} environment variable is read after processing
+any @value{GDBN} initialization files (@xref{Startup}) and after
+processing any commands passed using command line options (for
+example, @code{-ex}).
+
 @cindex remove duplicate history
 @kindex set history remove-duplicates
 @item set history remove-duplicates @var{count}
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index 097619d48d4..c51ec63eccf 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -497,8 +497,6 @@ gdb_test "set environment" "Argument required .environment variable and value.*"
 gdb_test "set height" "Argument required .integer to set it to.*"
 #test set history expansion
 gdb_test_no_output "set history expansion" "set history expansion"
-#test set history filename
-gdb_test "set history filename" "Argument required .filename to set it to.*"
 # Make sure the history ends up in the right place.
 gdb_test_no_output "set history filename [standard_output_file .gdb_history]" \
     "set the history filename"
diff --git a/gdb/testsuite/gdb.base/gdbinit-history.exp b/gdb/testsuite/gdb.base/gdbinit-history.exp
index 528c07dce30..baa1b49153c 100644
--- a/gdb/testsuite/gdb.base/gdbinit-history.exp
+++ b/gdb/testsuite/gdb.base/gdbinit-history.exp
@@ -128,6 +128,154 @@ proc test_no_truncation_of_unlimited_history_file { } {
     }
 }
 
+# Check that the current command history matches HIST, which is a list
+# of commands, oldest fist.
+proc check_history { hist } {
+
+    # The show commands we issue here always appears last in the
+    # commands list.
+    lappend hist "show commands"
+
+    # Number all of the entries in the HIST list and convert the list
+    # into a pattern to match against GDB.
+    set hist_lines [list]
+    set idx 1
+    foreach h $hist {
+	lappend hist_lines "    $idx  $h"
+	incr idx
+    }
+    set pattern [eval multi_line $hist_lines]
+
+    # Check the history.
+    gdb_test "show commands" "$pattern.*"
+}
+
+# Run 'show history filename' and check the output contains the
+# filename matching PATTERN, unless, PATTERN is the empty string, in
+# which case match a different output that GDB will give if the
+# history filename is the empty string.
+#
+# TESTNAME is the name for the test, which defaults to the command run
+# in the test.
+proc check_history_filename { pattern {testname ""} } {
+
+    set cmd "show history filename"
+    if { $testname == "" } {
+	set testname $cmd
+    }
+
+    if { $pattern == "" } {
+	gdb_test $cmd \
+	    "There is no filename currently set for recording the command history in." \
+	    $testname
+    } else {
+	gdb_test $cmd \
+	    "The filename in which to record the command history is \"$pattern\"\." \
+	    $testname
+    }
+}
+
+# Tests for how GDB handles setting the history filename to the empty
+# string.
+proc test_empty_history_filename { } {
+    global env
+    global gdb_prompt
+
+    set common_history [list "set height 0" "set width 0"]
+
+    set test_dir [standard_output_file history_test]
+    remote_exec host "mkdir -p $test_dir"
+    foreach entry { { ".gdb_history" "xxxxx" } \
+			{ "_gdb_history" "xxxxx" } \
+			{ "alt_history" "yyyyy" } } {
+	set fn [lindex $entry 0]
+	set content [lindex $entry 1]
+	set fd [open [standard_output_file "$test_dir/$fn"] w]
+	puts $fd "$content"
+	close $fd
+    }
+
+    with_cwd "$test_dir" {
+	with_test_prefix "load default history file" {
+	    # Start GDB and see that the history file was loaded
+	    # correctly.
+	    gdb_exit
+	    gdb_start
+	    check_history [concat "xxxxx" $common_history]
+	    check_history_filename ".*/.gdb_history"
+	}
+
+	with_test_prefix "load GDBHISTFILE history file" {
+	    # Now restart GDB with GDBHISTFILE set to see that the
+	    # "other" history file is loaded.
+	    save_vars { env(GDBHISTFILE) } {
+		setenv GDBHISTFILE \
+		    "$test_dir/alt_history"
+		gdb_exit
+		gdb_start
+		check_history [concat "yyyyy" $common_history]
+		check_history_filename ".*/alt_history"
+	    }
+	}
+
+	with_test_prefix "GDBHISTFILE is empty" {
+	    # Now restart GDB with GDBHISTFILE set to indicate don't
+	    # load any history file, check none was loaded.
+	    save_vars { env(GDBHISTFILE) } {
+	    setenv GDBHISTFILE ""
+		gdb_exit
+		gdb_start
+		check_history $common_history
+		check_history_filename ""
+	    }
+
+	    # Check that 'show history save' does the right thing when
+	    # the history filename is the empty string.
+	    gdb_test_no_output "set history save off" \
+		"ensure history save is off initially"
+	    gdb_test "show history save" \
+		"Saving of the history record on exit is off." \
+		"Check history save is off"
+	    gdb_test_no_output "set history save on"
+	    gdb_test "show history save" \
+		"Saving of the history is disabled due to the value of 'history filename'." \
+		"Check history save is off due to filename"
+	    gdb_test_no_output \
+		"set history filename $test_dir/alt_history" \
+		"set history filename at the command line"
+	    check_history_filename ".*/alt_history" \
+		"check filename after setting at the command line"
+	    gdb_test "show history save" \
+		"Saving of the history record on exit is on." \
+		"Check history save is on"
+	    gdb_test_no_output "set history filename"
+	    gdb_test "show history save" \
+		"Saving of the history is disabled due to the value of 'history filename'." \
+		"Check history save is off due to filename again"
+	    gdb_test_no_output "set history save off"
+	}
+
+	with_test_prefix "Use -ex to clear history file" {
+	    # Now restart GDB with the command line '-ex' to indicate
+	    # no history file should be loaded.
+	    gdb_exit
+	    if {[gdb_spawn_with_cmdline_opts \
+		     "-ex \"set history filename\""] != 0} {
+		fail "spawn"
+		return
+	    }
+	    set test "initial prompt"
+	    gdb_test_multiple "" $test {
+		-re ".*$gdb_prompt $" {
+		    pass "$test"
+		}
+	    }
+	    check_history [list]
+	    check_history_filename ""
+	}
+    }
+}
+
 test_gdbinit_history_setting "gdbinit-history/unlimited" "unlimited"
 test_gdbinit_history_setting "gdbinit-history/zero" "0"
 
@@ -138,3 +286,6 @@ test_no_truncation_of_unlimited_history_file
 # .gdbinit file.
 test_gdbinit_history_setting "gdbinit-history/unlimited" "1000" "1000"
 test_gdbinit_history_setting "gdbinit-history/unlimited" "unlimited" "foo"
+
+# Check handling of empty history filename.
+test_empty_history_filename
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 2d230b791ee..0dcb3177462 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5038,6 +5038,12 @@ proc gdb_init { test_file_name } {
     # tests.
     setenv TERM "dumb"
 
+    # Ensure that GDBHISTFILE and GDBHISTSIZE are removed from the
+    # environment, we don't want these modifications to the history
+    # settings.
+    unset -nocomplain ::env(GDBHISTFILE)
+    unset -nocomplain ::env(GDBHISTSIZE)
+
     # Initialize GDB's pty with a fixed size, to make sure we avoid pagination
     # during startup.  See "man expect" for details about stty_init.
     global stty_init
diff --git a/gdb/top.c b/gdb/top.c
index f702af9acd3..6765cb2005f 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -84,6 +84,8 @@
 
 extern void initialize_all_files (void);
 
+static bool history_filename_empty (void);
+
 #define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt
 #define PREFIX(X) the_prompts.prompt_stack[the_prompts.top + X].prefix
 #define SUFFIX(X) the_prompts.prompt_stack[the_prompts.top + X].suffix
@@ -884,13 +886,22 @@ static bool command_editing_p;
 
 /* static */ bool history_expansion_p;
 
+/* Should we write out the command history on exit?  In order to write out
+   the history both this flag must be true, and the history_filename
+   variable must be set to something sensible.  */
 static bool write_history_p;
+
+/* Implement 'show history save'.  */
 static void
 show_write_history_p (struct ui_file *file, int from_tty,
 		      struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("Saving of the history record on exit is %s.\n"),
-		    value);
+  if (!write_history_p || !history_filename_empty ())
+    fprintf_filtered (file, _("Saving of the history record on exit is %s.\n"),
+		      value);
+  else
+    fprintf_filtered (file, _("Saving of the history is disabled due to "
+			      "the value of 'history filename'.\n"));
 }
 
 /* The variable associated with the "set/show history size"
@@ -919,14 +930,30 @@ show_history_remove_duplicates (struct ui_file *file, int from_tty,
 		    value);
 }
 
+/* The name of the file in which GDB history will be written.  If this is
+   set to NULL, of the empty string then history will not be written.  */
 static char *history_filename;
+
+/* Return true if the history_filename is either NULL or the empty string,
+   indicating that we should not try to read, nor write out the history.  */
+static bool
+history_filename_empty (void)
+{
+  return (history_filename == nullptr || *history_filename == '\0');
+}
+
+/* Implement 'show history filename'.  */
 static void
 show_history_filename (struct ui_file *file, int from_tty,
 		       struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("The filename in which to record "
-			    "the command history is \"%ps\".\n"),
-		    styled_string (file_name_style.style (), value));
+  if (!history_filename_empty ())
+    fprintf_filtered (file, _("The filename in which to record "
+			      "the command history is \"%ps\".\n"),
+		      styled_string (file_name_style.style (), value));
+  else
+    fprintf_filtered (file, _("There is no filename currently set for "
+			      "recording the command history in.\n"));
 }
 
 /* This is like readline(), but it has some gdb-specific behavior.
@@ -2007,9 +2034,9 @@ init_history (void)
   set_readline_history_size (history_size_setshow_var);
 
   tmpenv = getenv ("GDBHISTFILE");
-  if (tmpenv)
+  if (tmpenv != nullptr)
     history_filename = xstrdup (tmpenv);
-  else if (!history_filename)
+  else if (history_filename == nullptr)
     {
       /* We include the current directory so that if the user changes
          directories the file written will be the same as the one
@@ -2024,7 +2051,9 @@ init_history (void)
       gdb::unique_xmalloc_ptr<char> temp (gdb_abspath (fname));
       history_filename = temp.release ();
     }
-  read_history (history_filename);
+
+  if (!history_filename_empty ())
+    read_history (history_filename);
 }
 
 static void
@@ -2093,6 +2122,8 @@ show_gdb_datadir (struct ui_file *file, int from_tty,
 				   gdb_datadir.c_str ()));
 }
 
+/* Implement 'set history filename'.  */
+
 static void
 set_history_filename (const char *args,
 		      int from_tty, struct cmd_list_element *c)
@@ -2100,7 +2131,7 @@ set_history_filename (const char *args,
   /* We include the current directory so that if the user changes
      directories the file written will be the same as the one
      that was read.  */
-  if (!IS_ABSOLUTE_PATH (history_filename))
+  if (!history_filename_empty () && !IS_ABSOLUTE_PATH (history_filename))
     {
       gdb::unique_xmalloc_ptr<char> temp (gdb_abspath (history_filename));
 
@@ -2207,7 +2238,7 @@ By default this option is set to 0."),
 			   show_history_remove_duplicates,
 			   &sethistlist, &showhistlist);
 
-  add_setshow_filename_cmd ("filename", no_class, &history_filename, _("\
+  add_setshow_optional_filename_cmd ("filename", no_class, &history_filename, _("\
 Set the filename in which to record the command history."), _("\
 Show the filename in which to record the command history."), _("\
 (the list of previous commands of which a record is kept)."),
