diff --git a/include/my_time.h b/include/my_time.h
index 6c53e39d1d86a7434aed3c97de2d175a2f08f5e8..d4dbe459c3bb336bd1c55cee9c8220d763fd6b3e 100644
--- a/include/my_time.h
+++ b/include/my_time.h
@@ -58,6 +58,8 @@ void init_time(void);
 my_time_t 
 my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap);
 
+void set_zero_time(MYSQL_TIME *tm);
+
 C_MODE_END
 
 #endif /* _my_time_h_ */
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index 3d49a594924529c645c229d95fb49f8b3ddf58c9..4a0335086f0f3d5426da1f70d19dbde75174e876 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -1587,9 +1587,10 @@ NetWare. */
 
 		fprintf(stderr,
 "InnoDB: You have now successfully upgraded to the multiple tablespaces\n"
-"InnoDB: format. You should NOT DOWNGRADE again to an earlier version of\n"
-"InnoDB: InnoDB! But if you absolutely need to downgrade, see section 4.6 of\n"
-"InnoDB: http://www.innodb.com/ibman.php for instructions.\n");
+"InnoDB: format. You should NOT DOWNGRADE to an earlier version of\n"
+"InnoDB: InnoDB! But if you absolutely need to downgrade, see\n"
+"InnoDB: http://dev.mysql.com/doc/mysql/en/Multiple_tablespaces.html\n"
+"InnoDB: for instructions.\n");
 	}
 
 	if (srv_force_recovery == 0) {
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 380e53d7d47d241d1cedb505971b7b579e0a0008..7d71998f37d05e4c3ca0aa01b65f27cc4f88ac0f 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -3167,13 +3167,6 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
  Fetch and conversion of result set rows (binary protocol).
 *********************************************************************/
 
-static void set_zero_time(MYSQL_TIME *tm)
-{
-  bzero((void *)tm, sizeof(*tm));
-  tm->time_type= MYSQL_TIMESTAMP_NONE;
-}
-
-
 /*
   Read date, (time, datetime) value from network buffer and store it
   in MYSQL_TIME structure.
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index fcfa2efef61ff546dc4fc40594e4ac712cea71de..4b5daf53bea5aeee24c2c4391b33c9fc609dc851 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -716,3 +716,13 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
   
   return (my_time_t) tmp;
 } /* my_system_gmt_sec */
+
+
+/* Set MYSQL_TIME structure to 0000-00-00 00:00:00.000000 */
+
+void set_zero_time(MYSQL_TIME *tm)
+{
+  bzero((void*) tm, sizeof(*tm));
+  tm->time_type= MYSQL_TIMESTAMP_NONE;
+}
+
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 708ca3a516f4ef7260863036dbce09617c6c644d..25b6434c1845b23776530007459a534a5999ad76 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -329,15 +329,22 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
 }
 
 #ifndef EMBEDDED_LIBRARY
+
+/*
+  Read date/time/datetime parameter values from network (binary
+  protocol). See writing counterparts of these functions in
+  libmysql.c (store_param_{time,date,datetime}).
+*/
+
 static void set_param_time(Item_param *param, uchar **pos, ulong len)
 {
-  ulong length;
-  uint day;
+  MYSQL_TIME tm;
+  ulong length= get_param_length(pos, len);
 
-  if ((length= get_param_length(pos, len)) >= 8)
+  if (length >= 8)
   {
     uchar *to= *pos;
-    TIME  tm;
+    uint day;
 
     tm.neg= (bool) to[0];
     day= (uint) sint4korr(to+1);
@@ -359,21 +366,22 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
       tm.second= 59;
     }
     tm.day= tm.year= tm.month= 0;
-
-    param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
-                    MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
   }
+  else
+    set_zero_time(&tm);
+  param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
+                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
   *pos+= length;
 }
 
 static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
 {
-  uint length;
+  MYSQL_TIME tm;
+  ulong length= get_param_length(pos, len);
 
-  if ((length= get_param_length(pos, len)) >= 4)
+  if (length >= 4)
   {
     uchar *to= *pos;
-    TIME  tm;
 
     tm.neg=    0;
     tm.year=   (uint) sint2korr(to);
@@ -394,21 +402,22 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
       tm.hour= tm.minute= tm.second= 0;
 
     tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
-
-    param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME, 
-                    MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
   }
+  else
+    set_zero_time(&tm);
+  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
+                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
   *pos+= length;
 }
 
 static void set_param_date(Item_param *param, uchar **pos, ulong len)
 {
-  ulong length;
- 
-  if ((length= get_param_length(pos, len)) >= 4)
+  MYSQL_TIME tm;
+  ulong length= get_param_length(pos, len);
+
+  if (length >= 4)
   {
     uchar *to= *pos;
-    TIME tm;
     /*
       Note, that though ranges of hour, minute and second are not checked
       here we rely on them being < 256: otherwise
@@ -421,10 +430,11 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
     tm.hour= tm.minute= tm.second= 0;
     tm.second_part= 0;
     tm.neg= 0;
-
-    param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
-                    MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
   }
+  else
+    set_zero_time(&tm);
+  param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
+                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
   *pos+= length;
 }
 
diff --git a/tests/client_test.c b/tests/client_test.c
index 552e49ec86236748f947cee7bbf7e148973e6da2..8a14fe3b4f77f80dc65e65e55cf4ad4342a7ea4e 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -10091,6 +10091,78 @@ static void test_bug5126()
 }
 
 
+static void test_bug4231()
+{
+  MYSQL_STMT *stmt;
+  MYSQL_BIND bind[2];
+  MYSQL_TIME tm[2];
+  const char *stmt_text;
+  int rc;
+
+  myheader("test_bug4231");
+
+  stmt_text= "DROP TABLE IF EXISTS t1";
+  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+  myquery(rc);
+
+  stmt_text= "CREATE TABLE t1 (a int)";
+  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+  myquery(rc);
+
+  stmt_text= "INSERT INTO t1 VALUES (1)";
+  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+  myquery(rc);
+
+  stmt= mysql_stmt_init(mysql);
+  stmt_text= "SELECT a FROM t1 WHERE ? = ?";
+  rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+  check_execute(stmt, rc);
+
+  /* Bind input buffers */
+  bzero(bind, sizeof(bind));
+  bzero(tm, sizeof(tm));
+
+  bind[0].buffer_type= MYSQL_TYPE_TIME;
+  bind[0].buffer= (void*) tm;
+  bind[1].buffer_type= MYSQL_TYPE_TIME;
+  bind[1].buffer= (void*) tm+1;
+
+  mysql_stmt_bind_param(stmt, bind);
+  check_execute(stmt, rc);
+
+  /*
+    First set server-side params to some non-zero non-equal values:
+    then we will check that they are not used when client sends
+    new (zero) times.
+  */
+  tm[0].time_type = MYSQL_TIMESTAMP_DATE;
+  tm[0].year = 2000;
+  tm[0].month = 1;
+  tm[0].day = 1;
+  tm[1]= tm[0];
+  --tm[1].year;                                 /* tm[0] != tm[1] */
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_fetch(stmt);
+
+  /* binds are unequal, no rows should be returned */
+  DBUG_ASSERT(rc == MYSQL_NO_DATA);
+
+  /* Set one of the dates to zero */
+  tm[0].year= tm[0].month= tm[0].day= 0;
+  tm[1]= tm[1];
+  mysql_stmt_execute(stmt);
+  rc= mysql_stmt_fetch(stmt);
+  DBUG_ASSERT(rc == 0);
+
+  mysql_stmt_close(stmt);
+  stmt_text= "DROP TABLE t1";
+  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+  myquery(rc);
+}
+
 /*
   Read and parse arguments and MySQL options from my.cnf
 */
@@ -10389,6 +10461,8 @@ int main(int argc, char **argv)
     test_bug4030();         /* test conversion string -> time types in
                                libmysql */
     test_bug5126();         /* support for mediumint type in libmysql */
+    test_bug4231();         /* proper handling of all-zero times and
+                               dates in the server */
     /*
       XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
       DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.