diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
index df777712c2a7f9ba7d6ccd69eb6de7bbbeb85c1c..0bf04dc134dbc38a6f5e321669da6dfcd7dedf45 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
@@ -76,7 +76,7 @@ public class PluginStarter implements Runnable {
             Properties props = new Properties();
             DataHelper.loadProps(props, clientConfig);
             List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
-            runClientApps(ctx, pluginDir, clients);
+            runClientApps(ctx, pluginDir, clients, true);
         }
 
         // start console webapps in console/webapps
@@ -142,6 +142,37 @@ public class PluginStarter implements Runnable {
         return true;
     }
 
+    /** @return true on success */
+    static boolean stopPlugin(RouterContext ctx, String appName) throws Exception {
+        Log log = ctx.logManager().getLog(PluginStarter.class);
+        File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
+        if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
+            log.error("Cannot stop nonexistent plugin: " + appName);
+            return false;
+        }
+
+        // stop things in clients.config
+        File clientConfig = new File(pluginDir, "clients.config");
+        if (clientConfig.exists()) {
+            Properties props = new Properties();
+            DataHelper.loadProps(props, clientConfig);
+            List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
+            runClientApps(ctx, pluginDir, clients, false);
+        }
+
+        // stop console webapps in console/webapps
+
+        // remove summary bar link
+        Properties props = pluginProperties(ctx, appName);
+        String name = props.getProperty("consoleLinkName_" + Messages.getLanguage(ctx));
+        if (name == null)
+            name = props.getProperty("consoleLinkName");
+        if (name != null && name.length() > 0)
+            NavHelper.unregisterApp(name);
+
+        return true;
+    }
+
     /** plugin.config */
     public static Properties pluginProperties(I2PAppContext ctx, String appName) {
         File cfgFile = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName + '/' + "plugin.config");
@@ -202,12 +233,21 @@ public class PluginStarter implements Runnable {
         return null;
     }
 
-    private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps) {
+    /** @param start true=start, false=stop */
+    private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, boolean start) {
         Log log = ctx.logManager().getLog(PluginStarter.class);
         for(ClientAppConfig app : apps) {
-            if (app.disabled)
+            if (start && app.disabled)
                 continue;
-            String argVal[] = LoadClientAppsJob.parseArgs(app.args);
+            String argVal[];
+            if (start) {
+                argVal = LoadClientAppsJob.parseArgs(app.args);
+            } else {
+                // stopargs must be present
+                if (app.stopargs == null || app.stopargs.length() <= 0)
+                    continue;
+                argVal = LoadClientAppsJob.parseArgs(app.stopargs);
+            }
             // do this after parsing so we don't need to worry about quoting
             for (int i = 0; i < argVal.length; i++) {
                 if (argVal[i].indexOf("$") >= 0) {
@@ -225,7 +265,7 @@ public class PluginStarter implements Runnable {
                 }
                 addToClasspath(cp, app.clientName, log);
             }
-            if (app.delay == 0) {
+            if (app.delay == 0 || !start) {
                 // run this guy now
                 LoadClientAppsJob.runClient(app.className, app.clientName, argVal, log);
             } else {
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java
index 7eb343a685fb18aac5dcd4a2bc6ead913997bb7b..c68346b99a8008cd6f2a6ec41fc9bc0a78822940 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java
@@ -287,7 +287,12 @@ public class PluginUpdateHandler extends UpdateHandler {
                     return;
                 }
 
-                // check if it is running now and stop it?
+                // check if it is running first?
+                try {
+                    if (!PluginStarter.stopPlugin(_context, appName)) {
+                        // failed, ignore
+                    }
+                } catch (Exception e) {} // ignore
 
             } else {
                 if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) {
diff --git a/router/java/src/net/i2p/router/startup/ClientAppConfig.java b/router/java/src/net/i2p/router/startup/ClientAppConfig.java
index 7afd0fc99237b2de97a22efc916a186b0515c8e4..3d57699a33811db3e9c33aea698b919f347469e3 100644
--- a/router/java/src/net/i2p/router/startup/ClientAppConfig.java
+++ b/router/java/src/net/i2p/router/startup/ClientAppConfig.java
@@ -35,6 +35,8 @@ public class ClientAppConfig {
     public boolean disabled;
     /** @since 0.7.12 */
     public String classpath;
+    /** @since 0.7.12 */
+    public String stopargs;
 
     public ClientAppConfig(String cl, String client, String a, long d, boolean dis) {
         className = cl;
@@ -45,9 +47,10 @@ public class ClientAppConfig {
     }
 
     /** @since 0.7.12 */
-    public ClientAppConfig(String cl, String client, String a, long d, boolean dis, String cp) {
+    public ClientAppConfig(String cl, String client, String a, long d, boolean dis, String cp, String sa) {
         this(cl, client, a, d, dis);
         classpath = cp;
+        stopargs = sa;
     }
 
     public static File configFile(I2PAppContext ctx) {
@@ -114,6 +117,7 @@ public class ClientAppConfig {
             String onBoot = clientApps.getProperty(PREFIX + i + ".onBoot");
             String disabled = clientApps.getProperty(PREFIX + i + ".startOnLoad");
             String classpath = clientApps.getProperty(PREFIX + i + ".classpath");
+            String stopargs = clientApps.getProperty(PREFIX + i + ".stopargs");
             i++;
             boolean dis = disabled != null && "false".equals(disabled);
 
@@ -125,12 +129,12 @@ public class ClientAppConfig {
             if (delayStr != null && !onStartup)
                 try { delay = 1000*Integer.parseInt(delayStr); } catch (NumberFormatException nfe) {}
 
-            rv.add(new ClientAppConfig(className, clientName, args, delay, dis, classpath));
+            rv.add(new ClientAppConfig(className, clientName, args, delay, dis, classpath, stopargs));
         }
         return rv;
     }
 
-    /** classpath not supported */
+    /** classpath and stopargs not supported */
     public static void writeClientAppConfig(RouterContext ctx, List apps) {
         File cfgFile = configFile(ctx);
         FileOutputStream fos = null;