diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index d0a0a0cdcd2b85f64a8b57c506667ebad2867e69..743e9cc3b693a3b5bdc7cb00fce7d9adb0d14707 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -14,49 +14,92 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-#include <stdlib.h>
 #include "client_priv.h"
 #include <my_dir.h>
 
-static my_bool opt_force=0, opt_verbose=0;
-static char *user= (char*)"root", *basedir=0, *datadir=0;
+static my_bool opt_force= 0, opt_verbose= 0, tty_password= 0;
+static char *user= (char*) "root", *basedir= 0, *datadir= 0, *opt_password= 0;
+static my_bool upgrade_defaults_created= 0;
+static my_string opt_mysql_port, opt_mysql_unix_port= 0;
+static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace";
+static my_bool info_flag= 0;
 
-static struct my_option my_long_options[] =
+static struct my_option my_long_options[]=
 {
   {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
    NO_ARG, 0, 0, 0, 0, 0, 0},
-  {"basedir", 'b', "Specifies the directory where MySQL is installed", (gptr*) &basedir,
+  {"basedir", 'b', "Specifies the directory where MySQL is installed",
+   (gptr*) &basedir,
    (gptr*) &basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
   {"datadir", 'd', "Specifies the data directory", (gptr*) &datadir,
    (gptr*) &datadir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef DBUG_OFF
+  {"debug", '#', "This is a non-debug version. Catch this and exit",
+   0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#else
+  {"debug", '#', "Output debug log", (gptr *) & default_dbug_option,
+   (gptr *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+  {"debug-info", 'T', "Print some debug info at exit.", (gptr *) & info_flag,
+   (gptr *) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
   {"force", 'f', "Continue even if we get an sql-error.",
    (gptr*) &opt_force, (gptr*) &opt_force, 0, GET_BOOL, NO_ARG, 0, 0,
    0, 0, 0, 0},
+  {"password", 'p',
+   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
+   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+  {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
+   (gptr*) &opt_mysql_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0,
+   0},
+  {"protocol", OPT_MYSQL_PROTOCOL,
+   "The protocol of connection (tcp,socket,pipe,memory).",
+   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"socket", 'S', "Socket file to use for connection.",
+   (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR,
+   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
   {"user", 'u', "User for login if not current user.", (gptr*) &user,
    (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-  {"verbose", 'v', "Display more output about the process", 0, 0, 0, GET_NO_ARG,
-   NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"verbose", 'v', "Display more output about the process", (gptr*) &opt_verbose,
+    (gptr *) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 };
-static const char *load_default_groups[] = { "mysql_upgrade", "client", 0 };
+static const char *load_default_groups[]=
+{
+  "mysql_upgrade", "client", 0
+};
 
 #include <help_end.h>
 
 static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
-	       char *argument __attribute__((unused)))
+get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)),
+               char *argument)
 {
-  switch(optid) {
+  switch (optid) {
   case '?':
-    puts("MySQL utility script to upgrade database to the current server version\n");
-    puts("\n");
+    puts
+      ("MySQL utility script to upgrade database to the current server version");
+    puts("");
     my_print_help(my_long_options);
     exit(0);
+  case '#':
+    DBUG_PUSH(argument ? argument : default_dbug_option);
+    break;
   case 'f':
     opt_force= TRUE;
     break;
-  case 'v':
-    opt_verbose= TRUE;
+  case 'p':
+    tty_password= 1;
+    if (argument)
+    {
+      char *start= argument;
+      my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
+      opt_password= my_strdup(argument, MYF(MY_FAE));
+      while (*argument)
+        *argument++= 'x';                       /* Destroy argument */
+      if (*start)
+        start[1]= 0;                            /* Cut length of argument */
+      tty_password= 0;
+    }
     break;
   default:;
   };
@@ -64,35 +107,104 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
 }
 
 
-static my_bool test_file_exists_res(const char *dir, const char *fname, char *buffer)
+/* buffer should be not smaller than FN_REFLEN */
+static my_bool test_file_exists_res(const char *dir, const char *fname,
+                                    char *buffer, char **buf_end)
 {
   MY_STAT stat_info;
 
-  if (fname)
-    sprintf(buffer, "%s/%s", dir, fname);
-  else
-    strcpy(buffer, dir);
+  *buf_end= strxnmov(buffer, FN_REFLEN-1, dir, "/", fname, NullS);
+  unpack_filename(buffer, buffer);
   return my_stat(buffer, &stat_info, MYF(0)) != 0;
 }
 
 
 static my_bool test_file_exists(const char *dir, const char *fname)
 {
-  char path[1024];
-  return test_file_exists_res(dir, fname, path);
+  char path[FN_REFLEN];
+  char *path_end;
+  return test_file_exists_res(dir, fname, path, &path_end);
+}
+
+
+static int create_check_file(const char *path)
+{
+  File check_file= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME));
+  int error;
+
+  if (check_file < 0)
+    return 1;
+
+  error= my_write(check_file, VERSION, strlen(VERSION), MYF(MY_WME | MY_FNABP));
+  error= my_close(check_file, MYF(MY_FAE | MY_WME)) || error;
+  return error;
+}
+
+
+static int create_defaults_file(const char *path, const char *our_defaults_path)
+{
+  uint b_read;
+  File our_defaults_file;
+  char buffer[512];
+  char *buffer_end;
+  int error;
+
+  /* check if the defaults file is needed at all */
+  if (!opt_password)
+    return 0;
+
+  File defaults_file= my_open(path, O_BINARY | O_CREAT | O_WRONLY,
+                              MYF(MY_FAE | MY_WME));
+
+  if (defaults_file < 0)
+    return 1;
+  upgrade_defaults_created= 1;
+  if (our_defaults_path)
+  {
+    our_defaults_file= my_open(our_defaults_path, O_RDONLY,
+                               MYF(MY_FAE | MY_WME));
+    if (our_defaults_file < 0)
+      return 1;
+    do
+    {
+      if (((b_read= my_read(our_defaults_file, buffer,
+                            sizeof(buffer), MYF(MY_WME))) == MY_FILE_ERROR) ||
+          my_write(defaults_file, buffer, b_read, MYF(MY_FNABP | MY_WME)))
+      {
+        error= 1;
+        goto close_return;
+      }
+    } while (b_read == sizeof(buffer));
+  }
+  buffer_end= strnmov(buffer, "\n[client]", sizeof(buffer));
+  if (opt_password)
+    buffer_end= strxnmov(buffer, sizeof(buffer),
+                         "\npassword=", opt_password, NullS);
+  error= my_write(defaults_file, buffer, (int) (buffer_end - buffer),
+                  MYF(MY_WME | MY_FNABP));
+close_return:
+  return my_close(defaults_file, MYF(MY_WME)) || error;
 }
 
 
 int main(int argc, char **argv)
 {
-  char bindir[1024];
-  char datadir_buf[1024];
-  char mysqlcheck_line[1024];
-  char check_file_name[1024];
+  char bindir[FN_REFLEN];
+  char *bindir_end, *buf_end;
+  char datadir_buf[FN_REFLEN];
+  char mysqlcheck_line[FN_REFLEN], *mysqlcheck_end;
+  char check_file_name[FN_REFLEN];
   int check_file;
-  char fix_priv_tables_cmd[1024];
-  char script_line[1024];
+  char fix_priv_tables_cmd[FN_REFLEN], *fix_cmd_end;
+  char script_line[FN_REFLEN];
   int error;
+  char *forced_defaults_file;
+  char *forced_extra_defaults;
+  char *defaults_group_suffix;
+  char upgrade_defaults_path[FN_REFLEN], *defaults_to_use= 0;
+  char port_socket[100], *port_socket_end;
+
+  MY_INIT(argv[0]);
 #ifdef __NETWARE__
   setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
 #endif
@@ -102,107 +214,187 @@ int main(int argc, char **argv)
   if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
     exit(error);
 
-  if (!basedir)
+  if (tty_password)
+    opt_password= get_tty_password(NullS);
+
+  /* Check if we want to force the use a specific default file */
+  get_defaults_options(argc, argv,
+                       &forced_defaults_file, &forced_extra_defaults,
+                       &defaults_group_suffix);
+
+  port_socket_end= port_socket;
+  if (opt_mysql_port)
+    port_socket_end= strxnmov(port_socket, sizeof(port_socket) - 1, " --port=",
+                              opt_mysql_port, NullS);
+  if (opt_mysql_unix_port)
+    port_socket_end= strxnmov(port_socket_end,
+                              sizeof(port_socket) -
+                                (int)(port_socket_end - port_socket) - 1,
+                              " --socket=", opt_mysql_unix_port, NullS);
+  *port_socket_end= 0;
+
+  if (basedir)
+  {
+    bindir_end= strmake(bindir, basedir, sizeof(bindir)-1);
+  }
+  else
   {
     if (test_file_exists("./share/mysql/english", "errmsg.sys")
         && (test_file_exists("./bin", "mysqld") ||
             test_file_exists("./libexec", "mysqld")))
     {
       getcwd(bindir, sizeof(bindir));
+      bindir_end= bindir + strlen(bindir);
     }
     else
     {
-      strcpy(bindir, DEFAULT_MYSQL_HOME);
+      bindir_end= strmake(bindir, DEFAULT_MYSQL_HOME, sizeof(bindir)-1);
     }
   }
-  else
-  {
-    strcpy(bindir, basedir);
-  }
 
   if (!datadir)
   {
     datadir= datadir_buf;
-    if (test_file_exists(bindir,"data/mysql"))
+    if (test_file_exists(bindir, "data/mysql"))
     {
-      sprintf(datadir, "%s/data", bindir);
+      *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/data", NullS)= 0;
     }
     else if (test_file_exists(bindir, "var/mysql"))
     {
-      sprintf(datadir, "%s/var", bindir);
+      *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/var", NullS)= 0;
     }
     else
-      strcpy(datadir, DATADIR);
+      datadir= (char*) DATADIR;
   }
 
-  strcat(bindir, "/bin");
+  strmake(bindir_end, "/bin", sizeof(bindir) - (int) (bindir_end - bindir)-1);
 
-  if (!test_file_exists(bindir, "mysqlcheck"))
+  if (!test_file_exists_res
+      (bindir, "mysqlcheck", mysqlcheck_line, &mysqlcheck_end))
   {
-    printf("Can't find program '%s/mysqlcheck'\n", bindir);
-    puts("Please restart with --basedir=mysql-install-directory\n");
+    printf("Can't find program '%s'\n", mysqlcheck_line);
+    puts("Please restart with --basedir=mysql-install-directory");
     exit(1);
   }
 
   if (!test_file_exists(datadir, "mysql/user.frm"))
   {
-    puts("Can't find data directory. Please restart with --datadir=path-to-data-dir\n");
+    puts
+      ("Can't find data directory. Please restart with --datadir=path-to-data-dir");
     exit(1);
   }
 
-  if (test_file_exists_res(datadir, "mysql_upgrade_info", check_file_name) && !opt_force)
+  /* create the modified defaults file to be used by mysqlcheck */
+  /* and mysql tools                                            */
+  *strxnmov(upgrade_defaults_path, sizeof(upgrade_defaults_path)-1,
+           datadir, "/upgrade_defaults", NullS)= 0;
+  unpack_filename(upgrade_defaults_path, upgrade_defaults_path);
+  if ((error=
+       create_defaults_file(upgrade_defaults_path, forced_extra_defaults)))
+    goto err_exit;
+
+  defaults_to_use= upgrade_defaults_created ?
+    upgrade_defaults_path : forced_extra_defaults;
+
+  if (test_file_exists_res(datadir, "mysql_upgrade_info", check_file_name,
+                           &buf_end) && !opt_force)
   {
-    char chf_buffer[10];
+    char chf_buffer[50];
     int b_read;
-    check_file= open(check_file_name, O_RDONLY);
-    b_read= read(check_file, chf_buffer, sizeof(chf_buffer));
+    check_file= my_open(check_file_name, O_RDONLY, MYF(0));
+    b_read= my_read(check_file, chf_buffer, sizeof(chf_buffer)-1, MYF(0));
     chf_buffer[b_read]= 0;
-    if (strcmp(chf_buffer, VERSION))
+    my_close(check_file, MYF(0));
+    if (!strcmp(chf_buffer, VERSION))
     {
       if (opt_verbose)
-        puts("mysql_upgrade already done for this version\n");
+        puts("mysql_upgrade already done for this version");
       goto fix_priv_tables;
     }
-    close(check_file);
   }
 
-  sprintf(mysqlcheck_line,
-          "%s/mysqlcheck --check-upgrade --all-databases --auto-repair --user=%s",
-          bindir, user);
+  if (defaults_to_use)
+  {
+    mysqlcheck_end= strxnmov(mysqlcheck_end,
+                             sizeof(mysqlcheck_line) - (int) (mysqlcheck_end -
+                                                              mysqlcheck_line),
+                             " --defaults-extra-file=", defaults_to_use,NullS);
+  }
+
+  mysqlcheck_end= strxnmov(mysqlcheck_end,
+                           sizeof(mysqlcheck_line) -
+                             (int) (mysqlcheck_end - mysqlcheck_line - 1),
+                           " --check-upgrade --all-databases --auto-repair --user=",
+                           user, port_socket, NullS);
+  *mysqlcheck_end= 0;
+
   if (opt_verbose)
     printf("Running %s\n", mysqlcheck_line);
-  system(mysqlcheck_line);
+  if ((error= system(mysqlcheck_line)))
+  {
+    printf("Error executing '%s'\n", mysqlcheck_line);
+    goto err_exit;
+  }
 
-  check_file= open(check_file_name, O_CREAT | O_WRONLY);
-  write(check_file, VERSION, strlen(VERSION));
-  close(check_file);
+  if ((error= create_check_file(check_file_name)))
+    goto err_exit;
 
 fix_priv_tables:
-  if (!test_file_exists(bindir, "mysql"))
+  if (!test_file_exists_res(bindir, "mysql", fix_priv_tables_cmd, &fix_cmd_end))
   {
-    puts("Could not find MySQL command-line client (mysql).\n");
-    puts("Please use --basedir to specify the directory where MySQL is installed.\n");
-    exit(1);
+    puts("Could not find MySQL command-line client (mysql).");
+    puts
+      ("Please use --basedir to specify the directory where MySQL is installed.");
+    error= 1;
+    goto err_exit;
   }
 
   if (!test_file_exists_res(basedir,
-        "support_files/mysql_fix_privilege_tables.sql", script_line) &&
-      !test_file_exists_res(basedir,
-        "share/mysql_fix_privileges_tables.sql", script_line) &&
-      !test_file_exists_res(basedir,
-        "share/mysql/mysql_fix_privilege_tables.sql", script_line) &&
-      !test_file_exists_res(basedir,
-        "scripts/mysql_fix_privilege_tables.sql", script_line) &&
-      !test_file_exists_res("/usr/local/mysql/share/mysql",
-        "mysql_fix_privilege_tables.sql", script_line))
+                            "support_files/mysql_fix_privilege_tables.sql",
+                            script_line, &buf_end)
+      && !test_file_exists_res(basedir, "share/mysql_fix_privilege_tables.sql",
+                               script_line, &buf_end)
+      && !test_file_exists_res(basedir,
+                               "share/mysql/mysql_fix_privilege_tables.sql",
+                               script_line, &buf_end)
+      && !test_file_exists_res(basedir,
+                               "scripts/mysql_fix_privilege_tables.sql",
+                               script_line, &buf_end)
+      && !test_file_exists_res("/usr/local/mysql/share/mysql",
+                               "mysql_fix_privilege_tables.sql", script_line,
+                               &buf_end))
   {
-    puts("Could not find file mysql_fix_privilege_tables.sql\n");
-    puts("Please use --basedir to specify the directory where MySQL is installed\n");
-    exit(1);
+    puts("Could not find file mysql_fix_privilege_tables.sql");
+    puts
+      ("Please use --basedir to specify the directory where MySQL is installed");
+    error= 1;
+    goto err_exit;
+  }
+
+  if (defaults_to_use)
+  {
+    fix_cmd_end= strxnmov(fix_cmd_end,
+                          sizeof(fix_priv_tables_cmd) -
+                            (int) (fix_cmd_end - fix_priv_tables_cmd - 1),
+                          " --defaults-extra-file=", defaults_to_use, NullS);
+  }
+  fix_cmd_end= strxnmov(fix_cmd_end,
+           sizeof(fix_priv_tables_cmd) - (int) (fix_cmd_end -
+                                                fix_priv_tables_cmd),
+           " --user=", user, port_socket, " mysql < ", script_line, NullS);
+  *fix_cmd_end= 0;
+
+  if ((error= system(fix_priv_tables_cmd)))
+  {
+    /* Problem is that the 'Duplicate column' error           */
+    /* which is not a bug for the script makes 'mysql' return */
+    /* an error                                               */
+    /* printf("Error executing '%s'\n", fix_priv_tables_cmd); */
   }
-    
-  sprintf(fix_priv_tables_cmd, "%s/mysql < %s", bindir, script_line);
-  system(fix_priv_tables_cmd);
 
+err_exit:
+  if (upgrade_defaults_created)
+    my_delete(upgrade_defaults_path, MYF(0));
+  my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
   return error;
-} /* main */
+}                                               /* main */