root账号的ssl_type修改为ANY后无法登录、
场景描述
在控制台以root帐号通过DAS登录实例时,报错Access denied。
原因分析
- 查看mysql.user表中的root帐号信息,排查客户端IP范围是否正确、是否使用SSL。
SELECT * FROM mysql.user WHERE User='root';
如果发现root帐号的ssl_type被设置为 ANY ,表明root帐号需要使用SSL连接。
- 查看SSL开启情况。
show variables like '%ssl%';
发现该实例未开启SSL:
因此,问题原因是自行修改root帐号的ssl_type为ANY后,导致无法登录。
解决方案
将root帐号的ssl_type修改为空即可,参考命令:
update mysql.user set ssl_type='' where user = 'root';
如果要将其他所有用户帐号的ssl_type修改为空,参考命令:
update mysql.user set ssl_type='' where user not like 'mysql%';
SSL使用与介绍
场景描述
使用SSL无法连接上数据库。
原因分析
优先检查网络是否已经连通,如果不带SSL的连接方式可以连接,则可能是mysql client或对应的数据库驱动的版本不兼容。
解决方案
GaussDB(for MySQL)是兼容社区8.0以上版本的,需要使用8.0及以上版本的mysql client或数据库驱动。
SSL(Secure Socket Layer:安全套接字层)使用数据加密、身份校验和消息完整性校验,为连接提供安全性保证。
SSL提供的功能主要包含 :
- 加密数据传输:利用对称密钥算法对传输的数据进行加密。
- 身份校验:基于证书使用数字签名的方法对客户端与服务器进行身份验证。
- 消息完整性校验:消息传输过程中使用MAC算法来检验消息的完整性。
注意
当服务端的SSL开启时,客户端的身份验证是可选的,即:即使服务端开启了SSL,客户端也可以不通过SSL的方式连接服务端,此时也可以正常通信,只是数据不会被加密。
如果不是通过SSL的方式,那么其在网络中的传输数据会以明文进行,存在安全隐患。
GaussDB(for MySQL)数据库服务端会默认开启服务端会默认开启SSL,客户业务使用时可以在客户端自行选择是否使用SSL。
使用mysql client连接时使用SSL的方式可参考:通过客户端连接GaussDB(for MySQL)
对各个IP地址的解释说明
购买GaussDB(for MySQL)实例后获得了多个IP地址,以1主1只读为例,在实例基础信息中最多共能找到4个IP,业务可以按自己的需要连接对应的IP。
说明对于节点读内网地址,如果出现节点故障,故障恢复前IP不可访问。
对于节点读内网地址,如果出现节点故障,故障恢复前IP不可访问。
- 主节点读内网地址(不推荐使用)
IP与节点绑定,可以从内网(同VPC网络内)直接连接IP做读写操作,如果发生故障倒换,节点变为只读节点,则该IP将只能做读操作,不能做写操作。对该IP的操作实际会落到对应的节点上。
- 只读节点读内网地址(不推荐使用)
IP与节点绑定,可以从内网(同VPC网络内)直接连接IP做读操作,如果发生故障倒换,节点变为主节点,则该IP将能做读写操作。对该IP的操作实际会落到对应的节点上。
- 读写内网地址
浮动IP,IP永远与主节点绑定,可以内网(同VPC网络内)直接连接IP做读写操作。如果发生故障倒换,该IP会浮动到新的主节点,依然可以做读写操作。对该IP的操作永远会落到当时的主节点上。
- 读写公网地址(创建实例后需要单独绑定)
创建并绑定公网IP后,可以从公网连接IP做读写操作。与浮动IP相同,也是一直与主节点绑定,且一直可以做读写操作。对该IP的操作永远会落到当时的主节点上。
说明故障倒换:
GaussDB(for MySQL)默认最少为2个节点,1主(可读可写)1只读(只可读不可写),主节点仅允许有一个,只读节点可以有多个。
当主节点遇到故障时,高可用系统会迅速发现,并选择一个只读节点将其升级为主节点,并将原主节点修复为只读节点,这个过程叫故障倒换。
客户端TLS版本MySQL不一致导致SSL连接失败
场景描述
某业务客户端连接到云上GaussDB(for MySQL)失败,但是连接到自建环境或其他环境可以成功,均使用了SSL连接。
原因分析
排查步骤:
- 查看GaussDB(for MySQL)的错误日志,观察到如下报错:
2021-07-09T10:30:58.476586+08:00 212539 [Warning] SSL errno: 337678594, SSL errmsg: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol2021-07-09T10:30:58.476647+08:00 212539 [Note] Bad handshake2021-07-09T10:32:43.535738+08:00 212631 [Warning] SSL errno: 337678594, SSL errmsg: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol2021-07-09T10:32:43.535787+08:00 212631 [Note] Bad handshake2021-07-09T10:50:03.401100+08:00 213499 [Warning] SSL errno: 337678594, SSL errmsg: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol2021-07-09T10:50:03.401161+08:00 213499 [Note] Bad handshake2021-07-09T10:53:44.458404+08:00 213688 [Warning] SSL errno: 337678594, SSL errmsg: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol2021-07-09T10:53:44.458475+08:00 213688 [Note] Bad handshake
- 从报错信息unsupported protocol可以看出,很可能和TLS版本相关,使用如下命令,分别查看GaussDB(for MySQL)和自建MySQL的TLS版本。
show variables like '%tls_version%';
发现GaussDB(for MySQL)为TLS v1.2版本,自建MySQL为TLS v1.1版本,存在差异。进一步确认客户端TLS版本,与自建MySQL一致,因此出现连接自建MySQL成功,连接云上GaussDB(for MySQL)失败。
解决方案
客户端升级TLS版本到TLS v1.2。
如果使用官方JDBC驱动 mysql-connector/J ,可参考官方文档,配置方法:
GaussDB(for MySQL)建立连接慢导致客户端超时
场景描述
业务在高峰期时,客户端经常出现向MySQL建立连接超时,导致系统登录需要十几秒。
原因分析
- 查看GaussDB(for MySQL)的错误日志,观察是否有如下信息:connection xxx is established slowly。示例:
有上述日志,说明存在某些连接超过一定时间仍未被MySQL处理,客户端的超时时间大于该时间,就会报错。
- 进一步查看线程池配置(默认开启),可以在控制台查看。
可以看出,threadpool_size为1,threadpool_stall_limit为500ms,threadpool_oversubscribe为3,线程池处理连接等待的时间主要与上述3个参数相关:
- 当线程池所有线程在忙碌,线程池中的调度线程会每隔500ms(threadpool_stall_limit)创建一个新线程,所以此时,每个线程组平均每500ms才能处理一个新的连接。如果队列太长,很可能导致客户端超时;
- 所有线程都在忙碌是指,工作线程达到线程池总线程数,在大量建立连接时,总线程数计算方法:threadpool_size*(threadpool_oversubscribe+1))
解决方案
对于存在大量新建连接,建议调大threadpool_oversubscribe增加线程总数。
减少线程重复创建与销毁部分的开销,提高性能,同时它也限制了MySQL的runing线程数,关键时刻可以保护系统,防止雪崩。
正常情况下,线程池适用于大量短连接的场景,如果客户是长连接,并且连接数量不多(客户端使用了连接池等情况),线程池的作用不大,此时调整threadpool_size和threadpool_oversubscribe两个参数扩大线程总数,或者直接关闭线程池。
连接数据库报错Access denied
场景描述
客户端连接数据库异常,返回错误:Error 1045: Access denied for user xxx
处理方法
- 连接了错误的主机
问题原因:业务连接了错误的数据库主机,该主机上相应用户或客户端IP没有权限访问。
解决方案:仔细检查要连接的数据库主机名,确保正确。
- 用户不存在
问题原因:客户端连接时,使用的用户不存在。
解决方案:
- 使用管理员帐户登录数据库,执行如下命令检查目标用户是否存在。
SELECT User FROM mysql.user WHERE User='xxx';
- 如果用户不存在,创建相应用户。
CREATE USER 'xxx'@'xxxxxx' IDENTIFIED BY 'xxxx';
- 用户存在,但客户端IP无访问权限
问题原因:客户端使用的用户存在,但是客户端IP没有该数据库的访问权限。
解决方案:
- 使用管理员帐户登录数据库,执行如下命令,检查目标用户允许哪些客户端IP连接。
SELECT Host, User FROM mysql.user WHERE User='xxx';
- 如果上述查询出的Host不包含客户端IP所在网段,则需要赋予相应访问权限。例如,赋予test用户192.168.0网段访问权限。
GRANT ALL PRIVILEGES ON *.* TO'root'@'192.168.0.%' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH PRIVILEGES;
- 密码错误
问题原因:用户对应的密码错误,或忘记密码
解决方案:
- 确定目标密码是否错误,由于密码用于身份验证,因此无法从MySQL以明文形式读取用户密码,但可以将密码的哈希字符串与目标密码的“PASSWORD”函数值进行比较,确定目标密码是否正确,示例SQL语句:
mysql> SELECT Host, User, authentication_string, PASSWORD('12345') FROM mysql.user WHERE User='test';
+-----------+------+-------------------------------------------+-------------------------------------------+
| Host | User | authentication_string | PASSWORD('12345') |
+-----------+------+-------------------------------------------+-------------------------------------------+
| % | test | *6A23DC5E7446019DC9C1778554ED87BE6BA61041 | *00A51F3F48415C7D4E8908980D443C29C69B60C9 |
+-----------+------+-------------------------------------------+-------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
2 rows in set, 1 warning (0.00 sec)
从上面例子可以看出,PASSWORD('12345')的哈希值与authentication_string列不匹配,这表明目标密码“12345”是错误的。
- 如果需要重置用户密码,参考如下SQL语句:
set password for 'test'@'%' = 'new_password';
- 密码包含特殊字符被Bash转义
问题原因:Linux默认的Bash环境下,使用命令行连接数据库,用户密码中包含特殊字符会被环境转义,导致密码失效。
例如,在Bash环境下,用户test的密码为“test$123”,使用命令mysql -hxxx -u test -ptest$123,连接数据库会报错ERROR 1045 (28000): Access denied。
解决方案:通过用单引号将密码括起来,防止Bash解释特殊字符。
mysql -hxxx -u test -p'test$123'
- 用户设置了REQUIRE SSL,但客户端使用非SSL连接
排查思路:
- 排查报错用户名是否强制使用SSL连接,执行:show create user 'xxx',如果出现“REQUIRE SSL”属性,说明该用户必须使用SSL连接。
- 排查是否使用过如下类似语句给用户授权。
GRANT ALL PRIVILEGES ON . TO 'ssluser'@'localhost' IDENTIFIED BY ' password ' REQUIRE SSL;
- 检查目标用户的ssl_type值,如果不为空,说明该用户需要使用SSL连接。
SELECT User, Host, ssl_type FROM mysql.user WHERE User='xxx';
解决方案:
- 客户端使用SSL方式数据库连接。
- 去除用户SSL连接权限,参考命令:ALTER USER 'username'@'host' REQUIRE NONE;
mariadb-connector SSL方式连接数据库失败
场景描述
使用jdbc无法连接数据库,报如下错误:
unable to find certification path to requested target
原因分析
从错误截图中可以看出,使用的是mariadb的jar包,而非MySQL的官方驱动包,而mariadb与官方的使用方法略有区别。
解决方案
对于mariadb的连接串应该为:
String url = "jdbc:mysql://xxx.xxx.xxx.xxx:xxxx/mysql?useSsl=true&serverSslCert=D:\\ca.pem&disableSslHostnameVerification=true";
注意:GaussDB(for MySQL)实例不支持hostname校验,因此需要设置disableSslHostnameVerification=true,不同mariadb jar包版本设置方式不同,可查看对应版本的使用说明。
使用root帐号连接数据库失败
场景描述
使用root帐号连接数据库失败。
原因分析
- 查看内核日志error.log,确认是否有拒绝连接的日志。
- 查看root权限,发现有两个root帐号,其中一个root限制host必须是IP必须是192开头。
解决方案
联系技术支持协助删除多余的root帐号。
客户端连接实例后会自动断开
故障描述
MySQL客户端连接实例后,会自动断开,报错信息:“ERROR 2013:Lost connection to MySQL server during query”。
解决方案
ERROR 2013是MySQL常见错误,一般为配置错误导致。
- “wait_timeout”:服务器关闭非交互连接之前等待活动的秒数。
- “interactive_timeout”:服务器关闭交互连接之前等待活动的秒数。
步骤 1 查看实例状态是否处于正常状态。
经查看实例状态正常,继续排查其他问题。
步骤 2 查看错误日志。
步骤 3 使用MySQL命令行客户端连接数据库,执行status命令,确认数据库实例是否频繁重启。
Uptime代表实例的运行时间,从排查结果可知,数据库并没有频繁重启,因而,客户端连接被断开,不是因数据库重启引起的。
步骤 4 查看“wait_timeout”和“interactive_timeout”参数设置,MySQL会自动断开超时的空连接。
步骤 5 您可根据实际应用需求量,修改“wait_timeout”和“interactive_timeout”参数值,无需重启实例。
步骤 6 恢复结果确认,等到10分钟左右,再次执行show databases命令,确认连接是否正常。
如图所示,说明连接正常。
istio-citadel证书机制导致每隔45天出现断连
场景描述
业务侧发现数据库每隔45天同一时间,多台数据库实例的连接数骤降。查看服务端连接数监控指标如下:
客户端出现大量报错如下:
原因分析
- 排查业务侧是否有间隔45天的定时任务。
- 客户端如果使用了istio等证书加密机制,分析证书相关日志,是否有如下类似信息。如果有,说明是证书过期导致。
客户端istio-citadel证书每隔45天过期,导致主动发起数据库断连请求。
解决方案
- 客户端设置合理的istio-citadel证书过期时间,并在过期发生时,主动规避操作。
- 客户端排查是否有其他证书过期问题。