diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result
index 26b3c1625aa09b2351120e04fbebea2f4ac3e18c..3e2e47ef740ea1dafb0d151a37f4b621d381a223 100644
--- a/mysql-test/r/warnings.result
+++ b/mysql-test/r/warnings.result
@@ -229,3 +229,59 @@ a
 select * from t1 limit 0, 0;
 a
 drop table t1;
+End of 4.1 tests
+CREATE TABLE t1( f1 CHAR(20) );
+CREATE TABLE t2( f1 CHAR(20), f2 CHAR(25) );
+CREATE TABLE t3( f1 CHAR(20), f2 CHAR(25), f3 DATE );
+INSERT INTO t1 VALUES ( 'a`' );
+INSERT INTO t2 VALUES ( 'a`', 'a`' );
+INSERT INTO t3 VALUES ( 'a`', 'a`', '1000-01-1' );
+DROP PROCEDURE IF EXISTS sp1;
+Warnings:
+Note	1305	PROCEDURE sp1 does not exist
+DROP PROCEDURE IF EXISTS sp2;
+Warnings:
+Note	1305	PROCEDURE sp2 does not exist
+DROP PROCEDURE IF EXISTS sp3;
+Warnings:
+Note	1305	PROCEDURE sp3 does not exist
+CREATE PROCEDURE sp1()
+BEGIN
+DECLARE x NUMERIC ZEROFILL;
+SELECT f1 INTO x FROM t1 LIMIT 1;
+END//
+CREATE PROCEDURE sp2()
+BEGIN
+DECLARE x NUMERIC ZEROFILL;
+SELECT f1 INTO x FROM t2 LIMIT 1;
+END//
+CREATE PROCEDURE sp3()
+BEGIN
+DECLARE x NUMERIC ZEROFILL;
+SELECT f1 INTO x FROM t3 LIMIT 1;
+END//
+CALL sp1();
+Warnings:
+Warning	1366	Incorrect decimal value: 'a`' for column 'x' at row 1
+CALL sp2();
+Warnings:
+Warning	1366	Incorrect decimal value: 'a`' for column 'x' at row 1
+CALL sp3();
+Warnings:
+Warning	1366	Incorrect decimal value: 'a`' for column 'x' at row 1
+DROP PROCEDURE IF EXISTS sp1;
+CREATE PROCEDURE sp1()
+BEGIN
+declare x numeric unsigned zerofill;
+SELECT f1 into x from t2 limit 1;
+END//
+CALL sp1();
+Warnings:
+Warning	1366	Incorrect decimal value: 'a`' for column 'x' at row 1
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP PROCEDURE sp1;
+DROP PROCEDURE sp2;
+DROP PROCEDURE sp3;
+End of 5.0 tests
diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test
index c20763f203f6fc5ac7b6a13b6d4fc4ecfef4db37..a8b8e5f51035c1899d2b4e7350cde1caab7472e5 100644
--- a/mysql-test/t/warnings.test
+++ b/mysql-test/t/warnings.test
@@ -147,4 +147,60 @@ select * from t1 limit 1, 0;
 select * from t1 limit 0, 0;
 drop table t1;
 
-# End of 4.1 tests
+--echo End of 4.1 tests
+
+#
+# Bug#20778: strange characters in warning message 1366 when called in SP
+#
+
+let $engine_type= innodb;
+
+CREATE TABLE t1( f1 CHAR(20) );
+CREATE TABLE t2( f1 CHAR(20), f2 CHAR(25) );
+CREATE TABLE t3( f1 CHAR(20), f2 CHAR(25), f3 DATE );
+
+INSERT INTO t1 VALUES ( 'a`' );
+INSERT INTO t2 VALUES ( 'a`', 'a`' );
+INSERT INTO t3 VALUES ( 'a`', 'a`', '1000-01-1' );
+
+DROP PROCEDURE IF EXISTS sp1;
+DROP PROCEDURE IF EXISTS sp2;
+DROP PROCEDURE IF EXISTS sp3;
+delimiter //;
+CREATE PROCEDURE sp1()
+BEGIN
+   DECLARE x NUMERIC ZEROFILL;
+   SELECT f1 INTO x FROM t1 LIMIT 1;
+END//
+CREATE PROCEDURE sp2()
+BEGIN
+   DECLARE x NUMERIC ZEROFILL;
+   SELECT f1 INTO x FROM t2 LIMIT 1;
+END//
+CREATE PROCEDURE sp3()
+BEGIN
+   DECLARE x NUMERIC ZEROFILL;
+   SELECT f1 INTO x FROM t3 LIMIT 1;
+END//
+delimiter ;//
+CALL sp1();
+CALL sp2();
+CALL sp3();
+
+DROP PROCEDURE IF EXISTS sp1;
+delimiter //;
+CREATE PROCEDURE sp1()
+BEGIN
+declare x numeric unsigned zerofill;
+SELECT f1 into x from t2 limit 1;
+END//
+delimiter ;//
+CALL sp1();
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP PROCEDURE sp1;
+DROP PROCEDURE sp2;
+DROP PROCEDURE sp3;
+
+--echo End of 5.0 tests
diff --git a/sql/field.cc b/sql/field.cc
index 2e478ead8b91aebef383be4a8b03492535d476c9..001c096d2c4f558198d299f7c4b8003f90272d6d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2365,11 +2365,16 @@ int Field_new_decimal::store(const char *from, uint length,
                       from, length, charset,  &decimal_value)) &&
       table->in_use->abort_on_warning)
   {
+    /* Because "from" is not NUL-terminated and we use %s in the ER() */
+    String from_as_str;
+    from_as_str.copy(from, length, &my_charset_bin);
+
     push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR,
                         ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
                         ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
-                        "decimal", from, field_name,
+                        "decimal", from_as_str.c_ptr(), field_name,
                         (ulong) table->in_use->row_count);
+
     DBUG_RETURN(err);
   }
 
@@ -2382,13 +2387,20 @@ int Field_new_decimal::store(const char *from, uint length,
     set_value_on_overflow(&decimal_value, decimal_value.sign());
     break;
   case E_DEC_BAD_NUM:
+    {
+      /* Because "from" is not NUL-terminated and we use %s in the ER() */
+      String from_as_str;
+      from_as_str.copy(from, length, &my_charset_bin);
+
     push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
                         ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
                         ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
-                        "decimal", from, field_name,
+                          "decimal", from_as_str.c_ptr(), field_name,
                         (ulong) table->in_use->row_count);
     my_decimal_set_zero(&decimal_value);
+
     break;
+    }
   }
 
 #ifndef DBUG_OFF