{"record":{"id":"59076a866c2ae0ce","repo":"alibaba/canal","slug":"canal-socketchannel-netty-not-support-ssl-mode","errorCode":null,"errorMessage":"canal socketChannel netty not support ssl mode: {}","messagePattern":"canal socketChannel netty not support ssl mode: (.+?)","errorType":"validation","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannelPool.java","lineNumber":34,"sourceCode":" */\npublic abstract class SocketChannelPool {\n\n    private static final Logger logger = LoggerFactory.getLogger(SocketChannelPool.class);\n\n    public static SocketChannel open(SocketAddress address) throws Exception {\n        String type = chooseSocketChannel();\n        if (\"netty\".equalsIgnoreCase(type)) {\n            return NettySocketChannelPool.open(address);\n        } else {\n            return BioSocketChannelPool.open(address);\n        }\n    }\n\n    public static SocketChannel connectSsl(SocketChannel channel, SslInfo sslInfo) throws IOException {\n        SslMode sslMode = sslInfo.getSslMode();\n        String type = chooseSocketChannel();\n        if (\"netty\".equalsIgnoreCase(type)) {\n            throw new UnsupportedOperationException(\"canal socketChannel netty not support ssl mode: \" + sslMode);\n        } else {\n            SocketAddress remoteSocketAddress = channel.getRemoteSocketAddress();\n            try {\n                return BioSocketChannelPool.openSsl(((BioSocketChannel) channel).getSocket(), sslInfo);\n            } catch (Exception e) {\n                if (sslMode == SslMode.PREFERRED) {\n                    // still use non ssl channel\n                    logger.info(\"{} still use non SSL channel due to SSL connect failed.\", remoteSocketAddress, e);\n                    return channel;\n                }\n                IOException ioe;\n                if (e instanceof IOException) {\n                    ioe = (IOException) e;\n                } else {\n                    ioe = new IOException(e);\n                }\n                throw ioe;\n            }","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/SocketChannelPool.java#L16-L52","documentation":"Thrown by SocketChannelPool.connectSsl(SocketChannel, SslInfo) when the chosen socket implementation is 'netty' (canal.socketChannel=netty) and an SslInfo is supplied. The netty SocketChannel implementation in canal has no SSL/TLS support wired in, so connectSsl refuses outright with UnsupportedOperationException naming the requested SslMode. Only the BIO path (BioSocketChannelPool.openSsl) implements SSL.","triggerScenarios":"Configuring canal.instance.db.sslMode (or otherwise supplying SslInfo) while canal.socketChannel=netty, then triggering a connection that calls SocketChannelPool.connectSsl. Any non-null SslInfo with the netty selector hits this throw regardless of the SslMode value.","commonSituations":"Enforcing TLS to MySQL (RDS/Aurora/CloudSQL requiring SSL) and having previously switched to netty for performance; upgrading canal and enabling SSL for compliance without realising the netty implementation lacks it; copying an instance config that sets both canal.socketChannel=netty and canal.instance.db.sslMode=REQUIRED.","solutions":["Remove canal.socketChannel=netty (or set canal.socketChannel=bio) — SSL is only supported on the BIO socket channel. This is the supported path for SSL connections.","If you must keep netty, drop the SSL requirement: clear canal.instance.db.sslMode / SslInfo so connectSsl is never invoked.","Verify which selector is active via System property or env var canal.socketChannel — env wins over -D in chooseSocketChannel().","On RDS/Aurora/CloudSQL that mandate TLS, stay on bio and set sslMode=REQUIRED (or VERIFY_CA / VERIFY_IDENTITY as needed)."],"exampleFix":"# before — conflicting config\ncanal.socketChannel = netty\ncanal.instance.db.sslMode = REQUIRED\n\n# after — SSL supported only on bio\ncanal.socketChannel = bio\ncanal.instance.db.sslMode = REQUIRED","handlingStrategy":"validation","validationCode":"String socketChannel = System.getenv(\"canal.socketChannel\");\nif (StringUtils.isEmpty(socketChannel)) {\n    socketChannel = System.getProperty(\"canal.socketChannel\");\n}\nboolean sslRequested = /* the SslInfo / canal.instance.db.sslMode is non-DISABLED */;\nif (\"netty\".equalsIgnoreCase(socketChannel) && sslRequested) {\n    throw new IllegalStateException(\n        \"SSL requires canal.socketChannel=bio; netty has no SSL support.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    SocketChannel ch = SocketChannelPool.connectSsl(existing, sslInfo);\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"netty not support ssl\")) {\n        log.error(\"SSL + netty is unsupported; switching to bio\");\n        // reconfigure canal.socketChannel=bio and reconnect, or drop SSL\n    }\n    throw e;\n}","preventionTips":["Never combine canal.socketChannel=netty with an SSL requirement — only BIO supports SSL.","When enforcing TLS to RDS/Aurora/CloudSQL, keep canal.socketChannel=bio (or unset).","Validate the SSL/mode pair at config-load time rather than at first connection.","Remember env var canal.socketChannel takes precedence over the -D system property."],"tags":["ssl","tls","netty","configuration","security","mysql"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}