diff --git a/include/my_sys.h b/include/my_sys.h
index 4a0586b9f2d73eaee642340e8a92b290e670426f..496ccdbcad585a2f7fd3707e5464c5074f0a9740 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -539,6 +539,7 @@ extern int my_close(File Filedes,myf MyFlags);
 extern File my_dup(File file, myf MyFlags);
 extern int my_mkdir(const char *dir, int Flags, myf MyFlags);
 extern int my_readlink(char *to, const char *filename, myf MyFlags);
+extern int my_is_symlink(const char *filename);
 extern int my_realpath(char *to, const char *filename, myf MyFlags);
 extern File my_create_with_symlink(const char *linkname, const char *filename,
 				   int createflags, int access_flags,
diff --git a/include/myisam.h b/include/myisam.h
index 0a8080707489a1996425707a82e129e27b5b503a..d45e734db60cef8a941dd86eacc4fdf120b7687d 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -195,6 +195,10 @@ extern my_bool myisam_concurrent_insert;
 extern my_off_t myisam_max_temp_length,myisam_max_extra_temp_length;
 extern ulong myisam_bulk_insert_tree_size, myisam_data_pointer_size;
 
+/* usually used to check if a symlink points into the mysql data home */
+/* which is normally forbidden                                        */
+extern int (*myisam_test_invalid_symlink)(const char *filename);
+
 	/* Prototypes for myisam-functions */
 
 extern int mi_close(struct st_myisam_info *file);
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 5bf1ff9464e6ec567ba631dc7a43f5ae6c7ec5b7..7d232b02ded3ba5928f308ff40101fcff9effe68 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -1610,7 +1610,7 @@ err:
 			    DATA_TMP_EXT, share->base.raid_chunks,
 			    (param->testflag & T_BACKUP_DATA ?
 			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
-	  mi_open_datafile(info,share,-1))
+	  mi_open_datafile(info,share,name,-1))
 	got_error=1;
     }
   }
@@ -2390,7 +2390,7 @@ err:
 			    DATA_TMP_EXT, share->base.raid_chunks,
 			    (param->testflag & T_BACKUP_DATA ?
 			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
-	  mi_open_datafile(info,share,-1))
+	  mi_open_datafile(info,share,name,-1))
 	got_error=1;
     }
   }
@@ -2927,7 +2927,7 @@ err:
 			    DATA_TMP_EXT, share->base.raid_chunks,
 			    (param->testflag & T_BACKUP_DATA ?
 			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
-	  mi_open_datafile(info,share,-1))
+	  mi_open_datafile(info,share,name,-1))
 	got_error=1;
     }
   }
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 7543bdf2bf154cbd2552dafc01d96fe55dd6796f..293c3b35886c426c178ebcbcf2083c87e8cf77c1 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -75,7 +75,7 @@ MI_INFO *test_if_reopen(char *filename)
 
 MI_INFO *mi_open(const char *name, int mode, uint open_flags)
 {
-  int lock_error,kfile,open_mode,save_errno,have_rtree=0;
+  int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err;
   uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
     key_parts,unique_key_parts,fulltext_keys,uniques;
   char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
@@ -95,7 +95,15 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
   head_length=sizeof(share_buff.state.header);
   bzero((byte*) &info,sizeof(info));
 
-  my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
+  realpath_err= my_realpath(name_buff,
+                  fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
+  if (my_is_symlink(org_name) &&
+      (realpath_err || (*myisam_test_invalid_symlink)(name_buff)))
+  {
+    my_errno= HA_WRONG_CREATE_OPTION;
+    DBUG_RETURN (NULL);
+  }
+
   pthread_mutex_lock(&THR_LOCK_myisam);
   if (!(old_info=test_if_reopen(name_buff)))
   {
@@ -449,7 +457,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
       lock_error=1;			/* Database unlocked */
     }
 
-    if (mi_open_datafile(&info, share, -1))
+    if (mi_open_datafile(&info, share, name, -1))
       goto err;
     errpos=5;
 
@@ -519,7 +527,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
       my_errno=EACCES;				/* Can't open in write mode */
       goto err;
     }
-    if (mi_open_datafile(&info, share, old_info->dfile))
+    if (mi_open_datafile(&info, share, name, old_info->dfile))
       goto err;
     errpos=5;
     have_rtree= old_info->rtree_recursion_state != NULL;
@@ -1153,12 +1161,30 @@ The argument file_to_dup is here for the future if there would on some OS
 exist a dup()-like call that would give us two different file descriptors.
 *************************************************************************/
 
-int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attribute__((unused)))
+int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *org_name,
+                     File file_to_dup __attribute__((unused)))
 {
+  char *data_name= share->data_file_name;
+  char real_data_name[FN_REFLEN];
+
+  if (org_name)
+  {
+    fn_format(real_data_name,org_name,"",MI_NAME_DEXT,4);
+    if (my_is_symlink(real_data_name))
+    {
+      if (my_realpath(real_data_name, real_data_name, MYF(0)) ||
+          (*myisam_test_invalid_symlink)(real_data_name))
+      {
+        my_errno= HA_WRONG_CREATE_OPTION;
+        return 1;
+      }
+      data_name= real_data_name;
+    }
+  }
 #ifdef USE_RAID
   if (share->base.raid_type)
   {
-    info->dfile=my_raid_open(share->data_file_name,
+    info->dfile=my_raid_open(data_name,
 			     share->mode | O_SHARE,
 			     share->base.raid_type,
 			     share->base.raid_chunks,
@@ -1167,8 +1193,7 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attr
   }
   else
 #endif
-    info->dfile=my_open(share->data_file_name, share->mode | O_SHARE,
-			MYF(MY_WME));
+    info->dfile=my_open(data_name, share->mode | O_SHARE, MYF(MY_WME));
   return info->dfile >= 0 ? 0 : 1;
 }
 
diff --git a/myisam/mi_static.c b/myisam/mi_static.c
index 9725c120f4421a76ebd03b481f25ea95480f48e2..881acd1d6206e5e85c683f5f173f153dfb6926db 100644
--- a/myisam/mi_static.c
+++ b/myisam/mi_static.c
@@ -43,6 +43,15 @@ my_off_t myisam_max_temp_length= MAX_FILE_SIZE;
 ulong    myisam_bulk_insert_tree_size=8192*1024;
 ulong    myisam_data_pointer_size=4;
 
+
+static int always_valid(const char *filename)
+{
+  return 0;
+}
+
+int (*myisam_test_invalid_symlink)(const char *filename)= always_valid;
+
+
 /*
   read_vec[] is used for converting between P_READ_KEY.. and SEARCH_
   Position is , == , >= , <= , > , <
diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c
index 34b89967ca79d70680a3472742f1b20d129483bb..01beb34ec56048ef61b42b56d9d74434f23513c9 100644
--- a/myisam/myisamchk.c
+++ b/myisam/myisamchk.c
@@ -1039,7 +1039,7 @@ static int myisamchk(MI_CHECK *param, my_string filename)
 	  error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
 				   raid_chunks,
 				   MYF(0));
-	  if (mi_open_datafile(info,info->s, -1))
+	  if (mi_open_datafile(info,info->s, NULL, -1))
 	    error=1;
 	  param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
 	  param->read_cache.file=info->dfile;
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index 6ed041e8b9d429854c44246c9dd237fe10722e14..59f1e40e5c21c9c039c7d669fec024a49ab1ac66 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -731,7 +731,8 @@ void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
 
 extern MI_INFO *test_if_reopen(char *filename);
 my_bool check_table_is_closed(const char *name, const char *where);
-int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup);
+int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *orn_name,
+                     File file_to_dup);
 int mi_open_keyfile(MYISAM_SHARE *share);
 void mi_setup_functions(register MYISAM_SHARE *share);
 
diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result
index 09715d3070330cdc78cffb01a21303b001281b9e..bf6e62d1f832cf72790e0e1575f1b451e066d934 100644
--- a/mysql-test/r/symlink.result
+++ b/mysql-test/r/symlink.result
@@ -138,13 +138,13 @@ drop table t1;
 deallocate prepare stmt;
 CREATE TABLE t1(a INT)
 DATA DIRECTORY='TEST_DIR/var/master-data/test';
-ERROR HY000: Incorrect arguments to DATA DIRECORY
+ERROR HY000: Incorrect arguments to DATA DIRECTORY
 CREATE TABLE t1(a INT)
 DATA DIRECTORY='TEST_DIR/var/master-data/';
-ERROR HY000: Incorrect arguments to DATA DIRECORY
+ERROR HY000: Incorrect arguments to DATA DIRECTORY
 CREATE TABLE t1(a INT)
 INDEX DIRECTORY='TEST_DIR/var/master-data';
-ERROR HY000: Incorrect arguments to INDEX DIRECORY
+ERROR HY000: Incorrect arguments to INDEX DIRECTORY
 CREATE TABLE t1(a INT)
 INDEX DIRECTORY='TEST_DIR/var/master-data_var';
 ERROR HY000: Can't create/write to file 'TEST_DIR/var/master-data_var/t1.MYI' (Errcode: 2)
diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test
index c8790c450f904b471398d881b0968f1ec6b5ebee..88c1ed9d7b3ae5bf684c1733b5777292589f30db 100644
--- a/mysql-test/t/symlink.test
+++ b/mysql-test/t/symlink.test
@@ -67,7 +67,7 @@ drop table t1;
 #
 
 disable_query_log;
---error 1103,1103
+--error 1210, 1210
 create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="tmp";
 
 # Check that we cannot link over a table from another database.
@@ -77,7 +77,7 @@ create database mysqltest;
 --error 1,1
 create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="/this-dir-does-not-exist";
 
---error 1103,1103
+--error 1210, 1210
 create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="not-hard-path";
 
 --error 1,1
diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c
index 7be3fcd36f0d3fade60cf8bc5f7e9b168081152e..4391d1fd00935d65a0804ad5f6f77d944b3e5fb3 100644
--- a/mysys/my_symlink.c
+++ b/mysys/my_symlink.c
@@ -107,38 +107,38 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags)
 #define BUFF_LEN FN_LEN
 #endif
 
+int my_is_symlink(const char *filename __attribute__((unused)))
+{
+  struct stat stat_buff;
+  return !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode);
+}
+
+
 int my_realpath(char *to, const char *filename,
 		myf MyFlags __attribute__((unused)))
 {
 #if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
   int result=0;
   char buff[BUFF_LEN];
-  struct stat stat_buff;
+  char *ptr;
   DBUG_ENTER("my_realpath");
 
-  if (!(MyFlags & MY_RESOLVE_LINK) ||
-      (!lstat(filename,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
+  DBUG_PRINT("info",("executing realpath"));
+  if ((ptr=realpath(filename,buff)))
+    strmake(to,ptr,FN_REFLEN-1);
+  else
   {
-    char *ptr;
-    DBUG_PRINT("info",("executing realpath"));
-    if ((ptr=realpath(filename,buff)))
-    {
-      strmake(to,ptr,FN_REFLEN-1);
-    }
-    else
-    {
-      /*
-	Realpath didn't work;  Use my_load_path() which is a poor substitute
-	original name but will at least be able to resolve paths that starts
-	with '.'.
-      */
-      DBUG_PRINT("error",("realpath failed with errno: %d", errno));
-      my_errno=errno;
-      if (MyFlags & MY_WME)
-	my_error(EE_REALPATH, MYF(0), filename, my_errno);
-      my_load_path(to, filename, NullS);
-      result= -1;
-    }
+    /*
+      Realpath didn't work;  Use my_load_path() which is a poor substitute
+      original name but will at least be able to resolve paths that starts
+      with '.'.
+    */
+    DBUG_PRINT("error",("realpath failed with errno: %d", errno));
+    my_errno=errno;
+    if (MyFlags & MY_WME)
+      my_error(EE_REALPATH, MYF(0), filename, my_errno);
+    my_load_path(to, filename, NullS);
+    result= -1;
   }
   DBUG_RETURN(result);
 #else
@@ -146,3 +146,4 @@ int my_realpath(char *to, const char *filename,
   return 0;
 #endif
 }
+
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 4b0031d1f2a860463d86669a8e68ced40ba0c54d..7e4e4ce7369bba91221ac87c16211c4a5dbdd140 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -892,6 +892,7 @@ extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
 	    mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[],
 	    mysql_unpacked_real_data_home[],
             def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
+extern int mysql_unpacked_real_data_home_len;
 #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
 extern MY_TMPDIR mysql_tmpdir_list;
 extern const char *command_name[];
@@ -1332,3 +1333,6 @@ bool check_stack_overrun(THD *thd,char *dummy);
 inline void kill_delayed_threads(void) {}
 #define check_stack_overrun(A, B) 0
 #endif
+
+
+extern "C" int test_if_data_home_dir(const char *dir);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 8111df7ad4df8ce993b40006448da865457aa015..2100446c12e53cfac2756efe8e0bae0774332bfd 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -391,6 +391,7 @@ char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
 char *language_ptr, *default_collation_name, *default_character_set_name;
 char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home;
 char mysql_unpacked_real_data_home[FN_REFLEN];
+int mysql_unpacked_real_data_home_len;
 struct passwd *user_info;
 char server_version[SERVER_VERSION_LENGTH];
 char *mysqld_unix_port, *opt_mysql_tmpdir;
@@ -5905,6 +5906,7 @@ static void mysql_init_variables(void)
   /* Things reset to zero */
   opt_skip_slave_start= opt_reckless_slave = 0;
   mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
+  myisam_test_invalid_symlink= test_if_data_home_dir;
   opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
   opt_disable_networking= opt_skip_show_db=0;
   opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0;
@@ -6897,9 +6899,11 @@ static void fix_paths(void)
     pos[1]= 0;
   }
   convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS);
-  (void) fn_format(buff, mysql_real_data_home, "", "",
-                   (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS));
-  (void) unpack_dirname(mysql_unpacked_real_data_home, buff);
+  my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0));
+  mysql_unpacked_real_data_home_len= strlen(mysql_unpacked_real_data_home);
+  if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR)
+    --mysql_unpacked_real_data_home_len;
+
   convert_dirname(language,language,NullS);
   (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
   (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4bbd425d80b850531ddf4aa8701e6ce6eb796ae9..b2b51894b62cc9ff2a79c0a023268b684642310a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -66,7 +66,6 @@ static bool append_file_to_dir(THD *thd, const char **filename_ptr,
              
 static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db,
   const char* alias);
-static bool test_if_data_home_dir(const char *dir);
 
 const char *any_db="*any*";	// Special symbol for check_access
 
@@ -2535,13 +2534,13 @@ mysql_execute_command(THD *thd)
 
     if (test_if_data_home_dir(lex->create_info.data_file_name))
     {
-      my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECORY");
+      my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECTORY");
       res= -1;
       break;
     }
     if (test_if_data_home_dir(lex->create_info.index_file_name))
     {
-      my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECORY");
+      my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECTORY");
       res= -1;
       break;
     }
@@ -5951,10 +5950,12 @@ Item *negate_expression(THD *thd, Item *expr)
     1	error  
 */
 
-static bool test_if_data_home_dir(const char *dir)
+C_MODE_START
+
+int test_if_data_home_dir(const char *dir)
 {
-  char path[FN_REFLEN], conv_path[FN_REFLEN];
-  uint dir_len, home_dir_len= strlen(mysql_unpacked_real_data_home);
+  char path[FN_REFLEN];
+  uint dir_len;
   DBUG_ENTER("test_if_data_home_dir");
 
   if (!dir)
@@ -5962,20 +5963,28 @@ static bool test_if_data_home_dir(const char *dir)
 
   (void) fn_format(path, dir, "", "",
                    (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS));
-  dir_len= unpack_dirname(conv_path, dir);
 
-  if (home_dir_len <= dir_len)
+  dir_len= strlen(path);
+  if (mysql_unpacked_real_data_home_len<= dir_len)
   {
+    if (dir_len > mysql_unpacked_real_data_home_len &&
+        path[mysql_unpacked_real_data_home_len] != FN_LIBCHAR)
+      DBUG_RETURN(0);
+
     if (lower_case_file_system)
     {
-      if (!my_strnncoll(default_charset_info, (const uchar*) conv_path,
-                        home_dir_len,
+      if (!my_strnncoll(default_charset_info, (const uchar*) path,
+                        mysql_unpacked_real_data_home_len,
                         (const uchar*) mysql_unpacked_real_data_home,
-                        home_dir_len))
+                        mysql_unpacked_real_data_home_len))
         DBUG_RETURN(1);
     }
-    else if (!memcmp(conv_path, mysql_unpacked_real_data_home, home_dir_len))
+    else if (!memcmp(path, mysql_unpacked_real_data_home,
+                     mysql_unpacked_real_data_home_len))
       DBUG_RETURN(1);
   }
   DBUG_RETURN(0);
 }
+
+C_MODE_END
+