How to Fix “Failed to Retrieve RMIServer Stub” JMX Connection Error in Java/Tomcat


10 views

The error message clearly indicates an SSL handshake failure despite having -Dcom.sun.management.jmxremote.ssl=false in your JVM parameters. This paradox occurs because Java's JMX/RMI implementation still attempts SSL negotiation even when explicitly disabled.

-Dcom.sun.management.jmxremote.port=8084
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
# Critical additions:
-Dcom.sun.management.jmxremote.rmi.port=8084
-Djava.rmi.server.hostname=your.private.ip.address

With dual NICs (public/private), Java may select the wrong interface for RMI communication. The RMI registry port (typically random) needs explicit binding:

# Verify ports are listening correctly:
sudo netstat -tulnp | grep java
# Should show both 8084 and the RMI port

# IPTables rules example:
iptables -I INPUT -p tcp --dport 8084 -j ACCEPT
iptables -I INPUT -p tcp --dport 30000:40000 -j ACCEPT  # For dynamic RMI ports

Your FQDN must resolve correctly on both client and server. Test with:

nslookup your.server.fqdn
ping your.server.fqdn  # From client machine

# Alternative connection URL format:
service:jmx:rmi://your.private.ip:8084/jndi/rmi://your.private.ip:8084/jmxrmi

For Tomcat deployments, modify setenv.sh:

CATALINA_OPTS="$CATALINA_OPTS \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=8084 \
-Dcom.sun.management.jmxremote.rmi.port=8084 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.rmi.server.hostname=$(hostname -i)"

As an alternative to VisualVM, try connecting with JConsole first:

jconsole your.server.fqdn:8084

# If connection fails, enable verbose logging:
java -Djavax.net.debug=all -jar jconsole.jar

Since you're using private DNS and NICs, ensure:

  • Routing tables prefer the private interface
  • No reverse path filtering is blocking traffic
  • TCP keepalive is enabled (add -Dsun.rmi.transport.tcp.responseTimeout=60000)

Here's a verified configuration that works in similar environments:

# Java startup parameters:
java -Dcom.sun.management.jmxremote \
     -Dcom.sun.management.jmxremote.port=8084 \
     -Dcom.sun.management.jmxremote.rmi.port=8084 \
     -Dcom.sun.management.jmxremote.ssl=false \
     -Dcom.sun.management.jmxremote.authenticate=false \
     -Djava.rmi.server.hostname=192.168.1.100 \  # Explicit private IP
     -Dsun.rmi.transport.tcp.responseTimeout=5000 \
     -Dsun.rmi.transport.proxy.connectTimeout=5000 \
     -jar your_application.jar

# Corresponding connection URL:
service:jmx:rmi:///jndi/rmi://192.168.1.100:8084/jmxrmi

When migrating Java applications between Windows and Linux environments, JMX connectivity issues often surface. The "Failed to retrieve RMIServer stub" error with SSL handshake failures suggests a fundamental mismatch in security expectations between client and server.

Your setup shows non-SSL JMX configuration:

-Dcom.sun.management.jmxremote.port=8084 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false

Yet the client (jvisualvm) appears to be attempting SSL negotiation, evident from the stack trace showing SSLHandshakeException.

First verify basic connectivity:

telnet your.fqdn.com 8084
nc -zv your.fqdn.com 8084

Then check if RMI registry is accessible:

curl http://your.fqdn.com:8084/jmxrmi

Option 1: Force plain RMI communication by adding these JVM parameters:

-Dcom.sun.management.jmxremote.rmi.port=8084
-Djava.rmi.server.hostname=your.fqdn.com
-Dcom.sun.management.jmxremote.local.only=false

Option 2: If SSL is required, configure it properly:

-Dcom.sun.management.jmxremote.ssl=true
-Djavax.net.ssl.keyStore=/path/to/keystore
-Djavax.net.ssl.keyStorePassword=changeit
-Djavax.net.ssl.trustStore=/path/to/truststore

For multi-homed hosts (like your dual-NIC setup), explicitly set the binding:

-Djava.rmi.server.hostname=private.nic.ip.address

As an alternative approach, try using jstatd:

jstatd -J-Djava.security.policy=jstatd.all.policy \
       -J-Djava.rmi.server.hostname=your.fqdn.com \
       -p 8084

With policy file jstatd.all.policy containing:

grant codebase "file:${java.home}/../lib/tools.jar" {
    permission java.security.AllPermission;
};

Verify JMX connectivity without GUI tools:

jconsole service:jmx:rmi:///jndi/rmi://your.fqdn.com:8084/jmxrmi

Even though port 8084 is open, RMI uses dynamic ports. You'll need to either:

  • Open a range (e.g., 30000-40000)
  • Fix RMI ports with: -Dcom.sun.management.jmxremote.port=8084 -Dcom.sun.management.jmxremote.rmi.port=8084