You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Ubuntu的Shiny App中通过SSH隧道连MySQL遇权限/连接错误求助

问题:Ubuntu虚拟机Shiny中SSH隧道连接MySQL失败(Windows正常)

环境与现象

Windows 10 RStudio中可正常运行的代码

library(RMySQL)
library(ssh)
library(callr)

rs <- r_session$new(wait = TRUE, wait_timeout = 3500)

rs$call(function(){
  session <- ssh::ssh_connect('<ssh-user>@<remote-ip-address>', keyfile = "<path-to-.pem-file>", verbose = FALSE)
  
  ssh::ssh_tunnel(session, port=3306, target = "127.0.0.1:3306")
})

# Connect to TRAQ DB.
Sys.sleep(1)

db-connection <- dbConnect(MySQL(), user = '<remote-user-name>', password = '<remote-password>', dbname = '<remote-database>', port=3306, host='127.0.0.1')

注:原代码中db-connection是无效变量名,R中不能用减号,实际运行需改为db_connection。

Ubuntu 22虚拟机Shiny中的错误

  • 使用localhost作为host时:
    ERROR 1044 (42000): Access denied for user '<remote-user-name>'@'localhost'
    
  • 使用127.0.0.1作为host时:
    ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1' (111)
    

还出现过错误码115的情况。

Ubuntu终端直接运行的修正方法

必须修改两处:

  1. 修改SSH隧道端口:
ssh::ssh_tunnel(session, port=3307, target = "127.0.0.1:3306")
  1. 对应修改DB连接端口:
db_connection <- dbConnect(MySQL(), user = '<remote-user-name>', password = '<remote-password>', dbname = '<remote-database>', port=3307, host='127.0.0.1')

若不改端口或使用localhost,会触发权限拒绝提示。

原因分析

  1. 端口占用差异:Windows上3306端口大概率未被本地MySQL占用,所以SSH隧道能正常绑定;但Ubuntu虚拟机默认可能安装并运行了本地MySQL服务,占用了3306端口,导致隧道无法创建,最终连接数据库时出现111错误(连接被拒绝)。
  2. MySQL连接方式差异:Ubuntu中localhost默认采用socket文件连接,而127.0.0.1强制使用TCP/IP连接。你的远程MySQL用户是授权给TCP连接的,用localhost时MySQL会匹配user@localhost的权限(该权限不存在),所以触发1044错误;而Windows上localhost默认走TCP/IP,因此能正常连接。

解决步骤

针对Shiny应用,按以下调整代码:

  1. 更换未占用端口:选一个本地未被使用的端口(如3307、3308),同步修改SSH隧道和DB连接的端口号。
  2. 强制TCP/IP连接:DB连接时始终用host='127.0.0.1',避开Ubuntu下socket连接的权限问题。
  3. 延长等待时间:把Sys.sleep(1)改为Sys.sleep(3)或更久,确保SSH隧道完全建立后再尝试连接数据库。
  4. 检查端口占用:在Ubuntu终端执行sudo lsof -i :3306,查看3306端口是否被本地MySQL占用。如果是,可停止本地服务(sudo systemctl stop mysql),或继续使用其他端口。

调整后的完整可用代码:

library(RMySQL)
library(ssh)
library(callr)

rs <- r_session$new(wait = TRUE, wait_timeout = 3500)

rs$call(function(){
  session <- ssh::ssh_connect('<ssh-user>@<remote-ip-address>', keyfile = "<path-to-.pem-file>", verbose = FALSE)
  
  # 使用未被占用的3307端口
  ssh::ssh_tunnel(session, port=3307, target = "127.0.0.1:3306")
})

# 延长等待时间,确保隧道建立完成
Sys.sleep(3)

# 修正变量名+使用对应端口和TCP/IP连接
db_connection <- dbConnect(MySQL(), 
                          user = '<remote-user-name>', 
                          password = '<remote-password>', 
                          dbname = '<remote-database>', 
                          port=3307, 
                          host='127.0.0.1')

额外注意事项

  • Shiny应用若部署在服务器环境,需确保防火墙允许使用所选端口(如3307)。
  • 开启SSH隧道的verbose=TRUE,可查看隧道建立的详细日志,方便排查连接问题。
  • 定期检查本地端口占用情况,避免后续端口被其他服务占用导致连接失败。

内容的提问来源于stack exchange,提问作者Garrett

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 02:15:37