diff -uN mysql-5.0.27/sql/mysqld.cc mysql-5.0.27-password_complexity/sql/mysqld.cc
--- mysql-5.0.27/sql/mysqld.cc	2006-10-20 17:22:27.000000000 -0700
+++ mysql-5.0.27-password_complexity/sql/mysqld.cc	2006-11-03 11:22:54.000000000 -0800
@@ -439,6 +439,8 @@
 const char *opt_date_time_formats[3];
 
 char *mysql_data_home= mysql_real_data_home;
+ulong mysql_pass_min_length = 8;
+ulong mysql_pass_complexity = 3;
 char server_version[SERVER_VERSION_LENGTH];
 char *mysqld_unix_port, *opt_mysql_tmpdir;
 const char **errmesg;			/* Error messages */
@@ -4772,6 +4774,10 @@
    NO_ARG, 0, 0, 0, 0, 0, 0},
   {"datadir", 'h', "Path to the database root.", (gptr*) &mysql_data_home,
    (gptr*) &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"pass-min-length", 0, "Minimum password length", (gptr*) &mysql_pass_min_length,
+   (gptr*) &mysql_pass_min_length, 0, GET_ULONG, OPT_ARG, 8, 1, 100, 0, 0, 0},
+  {"pass-complexity", 0, "Password complexity, how many char groups password must include.", (gptr*) &mysql_pass_complexity,
+   (gptr*) &mysql_pass_complexity, 0, GET_ULONG, OPT_ARG, 3, 1, 4, 0, 0, 0},
 #ifndef DBUG_OFF
   {"debug", '#', "Debug log.", (gptr*) &default_dbug_option,
    (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
@@ -7489,6 +7495,58 @@
   pthread_mutex_unlock(&LOCK_thread_count);
 }
 
+#include <ctype.h>
+
+/*
+    Verify password length matches mysql_pass_min_length.
+  SYNOPSIS
+    verify_password_min_length()
+    password  IN  NULL-terminated password string
+  RETURN
+    0 false, 1 true
+*/
+int
+verify_password_min_length(const char* password)
+{
+  return strlen(password) < mysql_pass_min_length;
+}
+
+/*
+    Verify password complexity matches mysql_pass_complexity.
+  SYNOPSIS
+    verify_password_complexity()
+    password  IN  NULL-terminated password string
+  RETURN
+    0 false, 1 true
+*/
+int
+verify_password_complexity(const char* password)
+{
+  size_t cnt;
+  uint8 hasDigit = 0;
+  uint8 hasLower = 0;
+  uint8 hasUpper = 0;
+  uint8 hasOther = 0;
+  
+  size_t string_length = strlen(password);
+  
+  for(cnt=0; cnt < string_length; cnt++)
+  {
+    if( isdigit(password[cnt]) )
+      hasDigit = 1;
+      
+    else if( islower(password[cnt]) )
+      hasLower = 1;
+    
+    else if( isupper(password[cnt]) )
+      hasUpper = 1;
+    
+    else if( !hasOther )
+      hasOther = 1;
+  }
+  
+  return (hasDigit + hasLower + hasUpper + hasOther) < mysql_pass_complexity;
+}
 
 /*****************************************************************************
   Instantiate have_xyx for missing storage engines
diff -uN mysql-5.0.27/sql/mysql_priv.h mysql-5.0.27-password_complexity/sql/mysql_priv.h
--- mysql-5.0.27/sql/mysql_priv.h	2006-10-20 17:22:53.000000000 -0700
+++ mysql-5.0.27-password_complexity/sql/mysql_priv.h	2006-11-03 08:57:29.000000000 -0800
@@ -1168,6 +1168,7 @@
 extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
 	    mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[],
             def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
+extern ulong mysql_pass_min_length, mysql_pass_complexity;
 #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
 extern MY_TMPDIR mysql_tmpdir_list;
 extern const char *command_name[];
diff -uN mysql-5.0.27/sql/set_var.cc mysql-5.0.27-password_complexity/sql/set_var.cc
--- mysql-5.0.27/sql/set_var.cc	2006-10-20 17:22:39.000000000 -0700
+++ mysql-5.0.27-password_complexity/sql/set_var.cc	2006-11-03 09:05:52.000000000 -0800
@@ -165,6 +165,8 @@
 sys_var_long_ptr	sys_connect_timeout("connect_timeout",
 					    &connect_timeout);
 sys_var_const_str       sys_datadir("datadir", mysql_real_data_home);
+sys_var_long_ptr        sys_pass_min_length("pass-min-length", &mysql_pass_min_length);
+sys_var_long_ptr        sys_pass_complexity("pass-complexity", &mysql_pass_complexity);
 sys_var_enum		sys_delay_key_write("delay_key_write",
 					    &delay_key_write_options,
 					    &delay_key_write_typelib,
@@ -629,6 +631,8 @@
   &sys_concurrent_insert,
   &sys_connect_timeout,
   &sys_datadir,
+  &sys_pass_min_length,
+  &sys_pass_complexity,
   &sys_date_format,
   &sys_datetime_format,
   &sys_div_precincrement,
@@ -839,6 +843,8 @@
   {sys_concurrent_insert.name,(char*) &sys_concurrent_insert,       SHOW_SYS},
   {sys_connect_timeout.name,  (char*) &sys_connect_timeout,         SHOW_SYS},
   {sys_datadir.name,          (char*) &sys_datadir,                 SHOW_SYS},
+  {sys_pass_min_length.name,  (char*) &sys_pass_min_length,         SHOW_SYS},
+  {sys_pass_complexity.name,  (char*) &sys_pass_complexity,         SHOW_SYS},
   {sys_date_format.name,      (char*) &sys_date_format,		    SHOW_SYS},
   {sys_datetime_format.name,  (char*) &sys_datetime_format,	    SHOW_SYS},
   {sys_default_week_format.name, (char*) &sys_default_week_format,  SHOW_SYS},
Common subdirectories: mysql-5.0.27/sql/share and mysql-5.0.27-password_complexity/sql/share
diff -uN mysql-5.0.27/sql/sql_yacc.yy mysql-5.0.27-password_complexity/sql/sql_yacc.yy
--- mysql-5.0.27/sql/sql_yacc.yy	2006-10-20 17:22:39.000000000 -0700
+++ mysql-5.0.27-password_complexity/sql/sql_yacc.yy	2006-11-03 10:40:16.000000000 -0800
@@ -8641,6 +8641,21 @@
 	   $$=$1; $1->password=$4;
 	   if ($4.length)
 	   {
+             /* verify length and complexity */
+             if(verify_password_min_length($4.str))
+             {
+	       my_error(ER_PASS_MIN_LENGTH,
+                          MYF(0), mysql_pass_min_length);
+               YYABORT;
+             }
+             if(verify_password_complexity($4.str))
+             {
+	      my_error(ER_PASS_COMPLEXITY,
+                         MYF(0), mysql_pass_complexity);
+               YYABORT;
+             }
+
+
              if (YYTHD->variables.old_passwords)
              {
                char *buff= 
--- mysql-5.0.27/sql/share/errmsg.txt	2006-10-20 17:22:37.000000000 -0700
+++ mysql-5.0.27-password_complexity/sql/share/errmsg.txt	2006-11-03 10:27:52.000000000 -0800
@@ -5633,4 +5633,8 @@
 	eng "String '%-.70s' is too long for %s (should be no longer than %d)"
 ER_NON_INSERTABLE_TABLE  
 	eng "The target table %-.100s of the %s is not insertable-into"
+ER_PASS_MIN_LENGTH
+	eng "Password less then minimum length [%d]"
+ER_PASS_COMPLEXITY
+	eng "Password does not meat complexity requirements [%d]"
 
diff -uN mysql-5.0.27/include/mysql_com.h mysql-5.0.27-password_complexity/include/mysql_com.h
--- mysql-5.0.27/include/mysql_com.h	2006-10-20 17:22:26.000000000 -0700
+++ mysql-5.0.27-password_complexity/include/mysql_com.h	2006-11-03 08:55:16.000000000 -0800
@@ -411,6 +411,8 @@
 void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st);
 
 void hash_password(unsigned long *to, const char *password, unsigned int password_len);
+int verify_password_min_length(const char* password);
+int verify_password_complexity(const char* password);
 void make_scrambled_password_323(char *to, const char *password);
 void scramble_323(char *to, const char *message, const char *password);
 my_bool check_scramble_323(const char *, const char *message,
