diff --git a/client/mysqltest.c b/client/mysqltest.c
index 8e72bc8edb8..ca4d9319707 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -66,7 +66,8 @@
 #ifndef WEXITSTATUS
 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
 #endif
-#define MAX_QUERY     131072
+/* MAX_QUERY is 256K -- there is a test in sp-big that is >128K */
+#define MAX_QUERY     (256*1024)
 #define MAX_VAR_NAME	256
 #define MAX_COLUMNS	256
 #define PAD_SIZE	128
diff --git a/mysql-test/r/sp-big.result b/mysql-test/r/sp-big.result
new file mode 100644
index 00000000000..004ff586aab
--- /dev/null
+++ b/mysql-test/r/sp-big.result
@@ -0,0 +1,15 @@
+drop procedure if exists test.longprocedure;
+drop table if exists t1;
+create table t1 (a int);
+insert into t1 values (1),(2),(3);
+length
+107520
+select length(routine_definition) from information_schema.routines where routine_schema = 'test' and routine_name = 'longprocedure';
+length(routine_definition)
+107530
+call test.longprocedure(@value);
+select @value;
+@value
+3
+drop procedure test.longprocedure;
+drop table t1;
diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result
index 277115733d4..d2872878cb9 100644
--- a/mysql-test/r/system_mysql_db.result
+++ b/mysql-test/r/system_mysql_db.result
@@ -172,7 +172,7 @@ proc	CREATE TABLE `proc` (
   `security_type` enum('INVOKER','DEFINER') NOT NULL default 'DEFINER',
   `param_list` blob NOT NULL,
   `returns` char(64) NOT NULL default '',
-  `body` blob NOT NULL,
+  `body` longblob NOT NULL,
   `definer` char(77) character set utf8 collate utf8_bin NOT NULL default '',
   `created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
   `modified` timestamp NOT NULL default '0000-00-00 00:00:00',
diff --git a/mysql-test/t/sp-big.test b/mysql-test/t/sp-big.test
new file mode 100644
index 00000000000..769d77dbef9
--- /dev/null
+++ b/mysql-test/t/sp-big.test
@@ -0,0 +1,33 @@
+#
+# Bug #11602: SP with very large body not handled well
+#
+
+--disable_warnings
+drop procedure if exists test.longprocedure;
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (a int);
+insert into t1 values (1),(2),(3);
+
+let $body=`select repeat('select count(*) into out1 from t1;\n', 3072)`;
+
+delimiter //;
+--disable_query_log
+eval select length('$body') as length//
+eval create procedure test.longprocedure (out out1 int) deterministic
+begin
+  $body
+end//
+--enable_query_log
+
+delimiter ;//
+
+# this is larger than the length above, because it includes the 'begin' and
+# 'end' bits and some whitespace
+select length(routine_definition) from information_schema.routines where routine_schema = 'test' and routine_name = 'longprocedure';
+
+call test.longprocedure(@value); select @value;
+
+drop procedure test.longprocedure;
+drop table t1;
diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh
index a3036b5c10b..383f8b80dc8 100644
--- a/scripts/mysql_create_system_tables.sh
+++ b/scripts/mysql_create_system_tables.sh
@@ -683,7 +683,7 @@ then
   c_p="$c_p   security_type     enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL,"
   c_p="$c_p   param_list        blob DEFAULT '' NOT NULL,"
   c_p="$c_p   returns           char(64) DEFAULT '' NOT NULL,"
-  c_p="$c_p   body              blob DEFAULT '' NOT NULL,"
+  c_p="$c_p   body              longblob DEFAULT '' NOT NULL,"
   c_p="$c_p   definer           char(77) collate utf8_bin DEFAULT '' NOT NULL,"
   c_p="$c_p   created           timestamp,"
   c_p="$c_p   modified          timestamp,"
diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql
index b93e0a47b1b..f67bab44514 100644
--- a/scripts/mysql_fix_privilege_tables.sql
+++ b/scripts/mysql_fix_privilege_tables.sql
@@ -426,7 +426,7 @@ CREATE TABLE IF NOT EXISTS proc (
   security_type     enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL,
   param_list        blob DEFAULT '' NOT NULL,
   returns           char(64) DEFAULT '' NOT NULL,
-  body              blob DEFAULT '' NOT NULL,
+  body              longblob DEFAULT '' NOT NULL,
   definer           char(77) collate utf8_bin DEFAULT '' NOT NULL,
   created           timestamp,
   modified          timestamp,
@@ -477,6 +477,7 @@ ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL,
                              'READS_SQL_DATA',
                              'MODIFIES_SQL_DATA'
                             ) DEFAULT 'CONTAINS_SQL' NOT NULL,
+                 MODIFY body longblob DEFAULT '' NOT NULL,
                  MODIFY sql_mode
                         set('REAL_AS_FLOAT',
                             'PIPES_AS_CONCAT',
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 459560ccac8..5dd5cd9c775 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5386,3 +5386,5 @@ ER_TRG_IN_WRONG_SCHEMA
 	eng "Trigger in wrong schema"
 ER_STACK_OVERRUN_NEED_MORE
 	eng "Thread stack overrun:  %ld bytes used of a %ld byte stack, and %ld bytes needed.  Use 'mysqld -O thread_stack=#' to specify a bigger stack."
+ER_TOO_LONG_BODY 42000 S1009
+	eng "Routine body for '%-.100s' is too long"
diff --git a/sql/sp.cc b/sql/sp.cc
index dec0eee0095..dfe3493528f 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -503,6 +503,11 @@ db_create_routine(THD *thd, int type, sp_head *sp)
       ret= SP_BAD_IDENTIFIER;
       goto done;
     }
+    if (sp->m_body.length > table->field[MYSQL_PROC_FIELD_BODY]->field_length)
+    {
+      ret= SP_BODY_TOO_LONG;
+      goto done;
+    }
     table->field[MYSQL_PROC_FIELD_DB]->
       store(sp->m_db.str, sp->m_db.length, system_charset_info);
     table->field[MYSQL_PROC_FIELD_NAME]->
diff --git a/sql/sp.h b/sql/sp.h
index b8af8d3a321..86351f61de9 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -29,6 +29,7 @@
 #define SP_INTERNAL_ERROR    -7
 #define SP_NO_DB_ERROR       -8
 #define SP_BAD_IDENTIFIER    -9
+#define SP_BODY_TOO_LONG    -10
 
 /* Drop all routines in database 'db' */
 int
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f1950d36b23..bf33f841eb8 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4107,6 +4107,12 @@ end_with_restore_list:
       delete lex->sphead;
       lex->sphead= 0;
       goto error;
+    case SP_BODY_TOO_LONG:
+      my_error(ER_TOO_LONG_BODY, MYF(0), name);
+      lex->unit.cleanup();
+      delete lex->sphead;
+      lex->sphead= 0;
+      goto error;
     default:
       my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
       lex->unit.cleanup();